//------------------------------------------------------------------------------ // // Copyright (c) Microsoft Corporation. All rights reserved. // //------------------------------------------------------------------------------ namespace System.Web.WebSockets { using System; using System.Web; // Contains miscellaneous utility methods for working with WebSockets internal static class WebSocketUtil { // Determines whether or not a given HttpWorkerRequest meets the requirements for "same-origin" // as called out in these two documents: // - http://tools.ietf.org/html/rfc6454 (Web Origin) // - http://tools.ietf.org/html/rfc6455 (WebSockets) public static bool IsSameOriginRequest(HttpWorkerRequest workerRequest) { string hostHeader = workerRequest.GetKnownRequestHeader(HttpWorkerRequest.HeaderHost); if (String.IsNullOrEmpty(hostHeader)) { // RFC 6455 (Sec. 4.1) and RFC 2616 (Sec. 14.23) make the "Host" header mandatory return false; } string secWebSocketOriginHeader = workerRequest.GetUnknownRequestHeader("Origin"); if (String.IsNullOrEmpty(secWebSocketOriginHeader)) { // RFC 6455 (Sec. 4.1) makes the "Origin" header mandatory for browser clients. // Phone apps, console clients, and similar non-browser clients aren't required to send the header, // but this method isn't intended for those use cases anyway, so we can fail them. (Note: it's still // possible for a non-browser app to send the appropriate Origin header.) return false; } // create URI instances from both the "Host" and the "Origin" headers Uri hostHeaderUri = null; Uri originHeaderUri = null; bool urisCreatedSuccessfully = Uri.TryCreate(workerRequest.GetProtocol() + "://" + hostHeader.Trim(), UriKind.Absolute, out hostHeaderUri) // RFC 2616 (Sec. 14.23): "Host" header doesn't contain the scheme, so we need to prepend && Uri.TryCreate(secWebSocketOriginHeader.Trim(), UriKind.Absolute, out originHeaderUri); if (!urisCreatedSuccessfully) { // construction of one of the Uri instances failed return false; } // RFC 6454 (Sec. 4), schemes must be normalized to lowercase. (And for WebSockets we only // support HTTP / HTTPS anyway.) if (originHeaderUri.Scheme != "http" && originHeaderUri.Scheme != "https") { return false; } // RFC 6454 (Sec. 5), comparisons should be ordinal. The Uri class will automatically // fill in the Port property using the default value for the scheme if the provided input doesn't // explicitly contain a port number. return hostHeaderUri.Scheme == originHeaderUri.Scheme && hostHeaderUri.Host == originHeaderUri.Host && hostHeaderUri.Port == originHeaderUri.Port; } } }