Click here to Skip to main content
15,885,309 members
Articles / Web Development / ASP.NET

Switching Between HTTP and HTTPS Automatically: Version 2

Rate me:
Please Sign up or sign in to vote.
4.91/5 (223 votes)
7 Feb 2011CPOL18 min read 3.5M   680  
An article on automatically switching between HTTP and HTTPS protocols without hard-coding absolute URLs
Imports System
Imports System.Globalization
Imports System.Web
Imports System.Web.Configuration
Imports Ventaur.Web.Security.Configuration

Namespace Ventaur.Web.Security

	''' <summary>
	''' Represents an evaluator for requests that 
	''' </summary>
	Public NotInheritable Class RequestEvaluator

		''' <summary>
		''' Evaluates a given request against specified settings for the type of security action required
		''' to fulfill the request properly.
		''' </summary>
		''' <param name="request">The request to evaluate.</param>
		''' <param name="settings">The settings to evaluate against.</param>
		''' <param name="forceEvaluation">
		''' A flag indicating whether or not to force evaluation, despite the mode set.
		''' </param>
		''' <returns>A SecurityType value for the appropriate action.</returns>
		Public Shared Function Evaluate(ByVal request As HttpRequest, ByVal settings As SecureWebPageSettings, ByVal forceEvaluation As Boolean) As SecurityType
			' Initialize the result to Ignore.
			Dim Result As SecurityType = SecurityType.Ignore

			' Determine if this request should be ignored based on the settings' Mode.
			Dim MustEvaluateRequest As Boolean = (forceEvaluation OrElse RequestMatchesMode(request, settings.Mode))
			DebugHelper.Output(If(MustEvaluateRequest, "Evaluating request...", "Evaluation of request skipped."))
			If MustEvaluateRequest Then
				' Make sure the request shouldn't be ignored as a HTTP handler.
				If settings.IgnoreHandlers = SecureWebPageIgnoreHandlers.BuiltIn AndAlso Not IsBuiltInHandlerRequest(request) OrElse _
				 settings.IgnoreHandlers = SecureWebPageIgnoreHandlers.WithStandardExtensions AndAlso Not IsStandardHandlerRequest(request) OrElse _
				 settings.IgnoreHandlers = SecureWebPageIgnoreHandlers.None Then
					' Get the relative file path of the current request from the application root.
					Dim RelativeFilePath As String = HttpUtility.UrlDecode(request.Url.AbsolutePath).Remove(0, request.ApplicationPath.Length).ToLower()
					If RelativeFilePath.StartsWith("/") Then
						' Remove any leading "/".
						RelativeFilePath = RelativeFilePath.Substring(1)
					End If

					' Get the relative directory of the current request by removing the last segment of the RelativeFilePath.
					Dim RelativeDirectory As String = String.Empty
					Dim i As Integer = RelativeFilePath.LastIndexOf("/"c)
					If i >= 0 Then
						RelativeDirectory = RelativeFilePath.Substring(0, i)
					End If

					' Determine if there is a matching file path for the current request.
					i = settings.Files.IndexOf(RelativeFilePath)
					If (i >= 0) Then
						Result = settings.Files(i).Secure
						DebugHelper.Output("Request matches file: {0} - {1}.", settings.Files(i).Secure, settings.Files(i).Path)
					Else
						' Try to find a matching directory path.
						Dim j As Integer = -1
						i = 0
						While i < settings.Directories.Count
							' Try to match the beginning of the directory if recursion is allowed (partial match).
							If (settings.Directories(i).Recurse AndAlso RelativeDirectory.StartsWith(settings.Directories(i).Path, StringComparison.CurrentCultureIgnoreCase) OrElse _
							 RelativeDirectory.Equals(settings.Directories(i).Path, StringComparison.CurrentCultureIgnoreCase)) AndAlso _
							 (j = -1 OrElse settings.Directories(i).Path.Length > settings.Directories(j).Path.Length) Then
								' First or longer partial match found (deepest recursion is the best match).
								j = i
							End If

							i += 1
						End While

						If j > -1 Then
							' Indicate a match for a partially matched directory allowing recursion.
							Result = settings.Directories(j).Secure
							DebugHelper.Output("Request matches directory: {0} - {1}.", settings.Directories(j).Secure, settings.Directories(j).Path)
						Else
							' No match indicates an insecure result.
							Result = SecurityType.Insecure
							DebugHelper.Output("Request does not match anything.")
						End If
					End If
				End If
			End If

			Return Result
		End Function

		''' <summary>
		''' Evaluates a given request against configured settings for the type of security action required
		''' to fulfill the request properly.
		''' </summary>
		''' <param name="request">The request to evaluate.</param>
		''' <returns>A SecurityType value for the appropriate action.</returns>
		Public Shared Function Evaluate(ByVal request As HttpRequest) As SecurityType
			' Get the settings for the secureWebPages section.
			Dim Settings As SecureWebPageSettings = TryCast(WebConfigurationManager.GetSection("secureWebPages"), SecureWebPageSettings)

			Return Evaluate(request, Settings, False)
		End Function

		''' <summary>
		''' Determines if the specified request is for one of the built-in HTTP handlers.
		''' </summary>
		''' <param name="request">The HttpRequest to test.</param>
		''' <returns>True if the request is for a built-in HTTP handler; false otherwise.</returns>
		Private Shared Function IsBuiltInHandlerRequest(ByVal request As HttpRequest) As Boolean
			' Get the file name of the request.
			Dim FileName As String = request.Url.Segments(request.Url.Segments.Length - 1)
			Return ( _
			 String.Compare(FileName, "trace.axd", True, CultureInfo.InvariantCulture) = 0 OrElse _
			 String.Compare(FileName, "webresource.axd", True, CultureInfo.InvariantCulture) = 0 _
			)
		End Function

		''' <summary>
		''' Determines if the specified request is for a standard HTTP handler (.axd).
		''' </summary>
		''' <param name="request">The HttpRequest to test.</param>
		''' <returns>True if the request is for a standard HTTP handler (.axd); false otherwise.</returns>
		Private Shared Function IsStandardHandlerRequest(ByVal request As HttpRequest) As Boolean
			Dim Path As String = request.Url.AbsolutePath
			Return ( _
				Path.EndsWith(".axd", True, CultureInfo.InvariantCulture) OrElse _
				Path.EndsWith(".ashx", True, CultureInfo.InvariantCulture) OrElse _
				Path.EndsWith(".asmx/js", true, CultureInfo.InvariantCulture) OrElse _
				Path.EndsWith(".asmx/jsdebug", true, CultureInfo.InvariantCulture) _
			)
		End Function

		''' <summary>
		''' Tests the given request to see if it matches the specified mode.
		''' </summary>
		''' <param name="request">A HttpRequest to test.</param>
		''' <param name="mode">The SecureWebPageMode used in the test.</param>
		''' <returns>
		'''		Returns true if the request matches the mode as follows:
		'''		<list type="disc">
		'''			<item>If mode is On.</item>
		'''			<item>If mode is set to RemoteOnly and the request is from a computer other than the server.</item>
		'''			<item>If mode is set to LocalOnly and the request is from the server.</item>
		'''		</list>
		'''	</returns>
		Private Shared Function RequestMatchesMode(ByVal request As HttpRequest, ByVal mode As SecureWebPageMode) As Boolean
			Select Case mode
				Case SecureWebPageMode.On
					Return True

				Case SecureWebPageMode.RemoteOnly
					Return (request.ServerVariables("REMOTE_ADDR") <> request.ServerVariables("LOCAL_ADDR"))

				Case SecureWebPageMode.LocalOnly
					Return (request.ServerVariables("REMOTE_ADDR") = request.ServerVariables("LOCAL_ADDR"))

				Case Else
					Return False
			End Select
		End Function

	End Class

End Namespace

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Web Developer
United States United States
I began programming on my Commodore 64 at around the age of 12. After migrating to DOS and then Windows, I decided to take on the Web. Several languages and platforms later, I have settled in with .NET nicely. I am currently the owner of a software consulting company and lead application developer for a learning-based technology consultation company.

The love of a finished application is usually at war with the desire to improve it as soon as it's released (they're never really finished).

Comments and Discussions