mirror of
				https://github.com/jellyfin/jellyfin.git
				synced 2025-11-03 19:17:24 -05:00 
			
		
		
		
	
		
			
				
	
	
		
			664 lines
		
	
	
		
			21 KiB
		
	
	
	
		
			C#
		
	
	
	
	
	
			
		
		
	
	
			664 lines
		
	
	
		
			21 KiB
		
	
	
	
		
			C#
		
	
	
	
	
	
using System;
 | 
						|
using System.Collections.Specialized;
 | 
						|
using System.Globalization;
 | 
						|
using System.IO;
 | 
						|
using System.Net;
 | 
						|
using System.Security.Cryptography.X509Certificates;
 | 
						|
using System.Text;
 | 
						|
using System.Threading.Tasks;
 | 
						|
using MediaBrowser.Model.Net;
 | 
						|
using MediaBrowser.Model.Services;
 | 
						|
using MediaBrowser.Model.Text;
 | 
						|
using SocketHttpListener.Primitives;
 | 
						|
 | 
						|
namespace SocketHttpListener.Net
 | 
						|
{
 | 
						|
    public sealed class HttpListenerRequest
 | 
						|
    {
 | 
						|
        string[] accept_types;
 | 
						|
        Encoding content_encoding;
 | 
						|
        long content_length;
 | 
						|
        bool cl_set;
 | 
						|
        CookieCollection cookies;
 | 
						|
        WebHeaderCollection headers;
 | 
						|
        string method;
 | 
						|
        Stream input_stream;
 | 
						|
        Version version;
 | 
						|
        QueryParamCollection query_string; // check if null is ok, check if read-only, check case-sensitiveness
 | 
						|
        string raw_url;
 | 
						|
        Uri url;
 | 
						|
        Uri referrer;
 | 
						|
        string[] user_languages;
 | 
						|
        HttpListenerContext context;
 | 
						|
        bool is_chunked;
 | 
						|
        bool ka_set;
 | 
						|
        bool? _keepAlive;
 | 
						|
 | 
						|
        private readonly ITextEncoding _textEncoding;
 | 
						|
 | 
						|
        internal HttpListenerRequest(HttpListenerContext context, ITextEncoding textEncoding)
 | 
						|
        {
 | 
						|
            this.context = context;
 | 
						|
            _textEncoding = textEncoding;
 | 
						|
            headers = new WebHeaderCollection();
 | 
						|
            version = HttpVersion.Version10;
 | 
						|
        }
 | 
						|
 | 
						|
        static char[] separators = new char[] { ' ' };
 | 
						|
 | 
						|
        internal void SetRequestLine(string req)
 | 
						|
        {
 | 
						|
            string[] parts = req.Split(separators, 3);
 | 
						|
            if (parts.Length != 3)
 | 
						|
            {
 | 
						|
                context.ErrorMessage = "Invalid request line (parts).";
 | 
						|
                return;
 | 
						|
            }
 | 
						|
 | 
						|
            method = parts[0];
 | 
						|
            foreach (char c in method)
 | 
						|
            {
 | 
						|
                int ic = (int)c;
 | 
						|
 | 
						|
                if ((ic >= 'A' && ic <= 'Z') ||
 | 
						|
                    (ic > 32 && c < 127 && c != '(' && c != ')' && c != '<' &&
 | 
						|
                     c != '<' && c != '>' && c != '@' && c != ',' && c != ';' &&
 | 
						|
                     c != ':' && c != '\\' && c != '"' && c != '/' && c != '[' &&
 | 
						|
                     c != ']' && c != '?' && c != '=' && c != '{' && c != '}'))
 | 
						|
                    continue;
 | 
						|
 | 
						|
                context.ErrorMessage = "(Invalid verb)";
 | 
						|
                return;
 | 
						|
            }
 | 
						|
 | 
						|
            raw_url = parts[1];
 | 
						|
            if (parts[2].Length != 8 || !parts[2].StartsWith("HTTP/"))
 | 
						|
            {
 | 
						|
                context.ErrorMessage = "Invalid request line (version).";
 | 
						|
                return;
 | 
						|
            }
 | 
						|
 | 
						|
            try
 | 
						|
            {
 | 
						|
                version = new Version(parts[2].Substring(5));
 | 
						|
                if (version.Major < 1)
 | 
						|
                    throw new Exception();
 | 
						|
            }
 | 
						|
            catch
 | 
						|
            {
 | 
						|
                context.ErrorMessage = "Invalid request line (version).";
 | 
						|
                return;
 | 
						|
            }
 | 
						|
        }
 | 
						|
 | 
						|
        void CreateQueryString(string query)
 | 
						|
        {
 | 
						|
            if (query == null || query.Length == 0)
 | 
						|
            {
 | 
						|
                query_string = new QueryParamCollection();
 | 
						|
                return;
 | 
						|
            }
 | 
						|
 | 
						|
            query_string = new QueryParamCollection();
 | 
						|
            if (query[0] == '?')
 | 
						|
                query = query.Substring(1);
 | 
						|
            string[] components = query.Split('&');
 | 
						|
            foreach (string kv in components)
 | 
						|
            {
 | 
						|
                int pos = kv.IndexOf('=');
 | 
						|
                if (pos == -1)
 | 
						|
                {
 | 
						|
                    query_string.Add(null, WebUtility.UrlDecode(kv));
 | 
						|
                }
 | 
						|
                else
 | 
						|
                {
 | 
						|
                    string key = WebUtility.UrlDecode(kv.Substring(0, pos));
 | 
						|
                    string val = WebUtility.UrlDecode(kv.Substring(pos + 1));
 | 
						|
 | 
						|
                    query_string.Add(key, val);
 | 
						|
                }
 | 
						|
            }
 | 
						|
        }
 | 
						|
 | 
						|
        internal void FinishInitialization()
 | 
						|
        {
 | 
						|
            string host = UserHostName;
 | 
						|
            if (version > HttpVersion.Version10 && (host == null || host.Length == 0))
 | 
						|
            {
 | 
						|
                context.ErrorMessage = "Invalid host name";
 | 
						|
                return;
 | 
						|
            }
 | 
						|
 | 
						|
            string path;
 | 
						|
            Uri raw_uri = null;
 | 
						|
            if (MaybeUri(raw_url.ToLowerInvariant()) && Uri.TryCreate(raw_url, UriKind.Absolute, out raw_uri))
 | 
						|
                path = raw_uri.PathAndQuery;
 | 
						|
            else
 | 
						|
                path = raw_url;
 | 
						|
 | 
						|
            if ((host == null || host.Length == 0))
 | 
						|
                host = UserHostAddress;
 | 
						|
 | 
						|
            if (raw_uri != null)
 | 
						|
                host = raw_uri.Host;
 | 
						|
 | 
						|
            int colon = host.LastIndexOf(':');
 | 
						|
            if (colon >= 0)
 | 
						|
                host = host.Substring(0, colon);
 | 
						|
 | 
						|
            string base_uri = String.Format("{0}://{1}:{2}",
 | 
						|
                (IsSecureConnection) ? (IsWebSocketRequest ? "wss" : "https") : (IsWebSocketRequest ? "ws" : "http"),
 | 
						|
                                host, LocalEndPoint.Port);
 | 
						|
 | 
						|
            if (!Uri.TryCreate(base_uri + path, UriKind.Absolute, out url))
 | 
						|
            {
 | 
						|
                context.ErrorMessage = WebUtility.HtmlEncode("Invalid url: " + base_uri + path);
 | 
						|
                return; return;
 | 
						|
            }
 | 
						|
 | 
						|
            CreateQueryString(url.Query);
 | 
						|
 | 
						|
            if (version >= HttpVersion.Version11)
 | 
						|
            {
 | 
						|
                string t_encoding = Headers["Transfer-Encoding"];
 | 
						|
                is_chunked = (t_encoding != null && String.Compare(t_encoding, "chunked", StringComparison.OrdinalIgnoreCase) == 0);
 | 
						|
                // 'identity' is not valid!
 | 
						|
                if (t_encoding != null && !is_chunked)
 | 
						|
                {
 | 
						|
                    context.Connection.SendError(null, 501);
 | 
						|
                    return;
 | 
						|
                }
 | 
						|
            }
 | 
						|
 | 
						|
            if (!is_chunked && !cl_set)
 | 
						|
            {
 | 
						|
                if (String.Compare(method, "POST", StringComparison.OrdinalIgnoreCase) == 0 ||
 | 
						|
                    String.Compare(method, "PUT", StringComparison.OrdinalIgnoreCase) == 0)
 | 
						|
                {
 | 
						|
                    context.Connection.SendError(null, 411);
 | 
						|
                    return;
 | 
						|
                }
 | 
						|
            }
 | 
						|
 | 
						|
            if (String.Compare(Headers["Expect"], "100-continue", StringComparison.OrdinalIgnoreCase) == 0)
 | 
						|
            {
 | 
						|
                var output = (HttpResponseStream)context.Connection.GetResponseStream(true);
 | 
						|
 | 
						|
                var _100continue = _textEncoding.GetASCIIEncoding().GetBytes("HTTP/1.1 100 Continue\r\n\r\n");
 | 
						|
 | 
						|
                output.InternalWrite(_100continue, 0, _100continue.Length);
 | 
						|
            }
 | 
						|
        }
 | 
						|
 | 
						|
        static bool MaybeUri(string s)
 | 
						|
        {
 | 
						|
            int p = s.IndexOf(':');
 | 
						|
            if (p == -1)
 | 
						|
                return false;
 | 
						|
 | 
						|
            if (p >= 10)
 | 
						|
                return false;
 | 
						|
 | 
						|
            return IsPredefinedScheme(s.Substring(0, p));
 | 
						|
        }
 | 
						|
 | 
						|
        //
 | 
						|
        // Using a simple block of if's is twice as slow as the compiler generated
 | 
						|
        // switch statement.   But using this tuned code is faster than the
 | 
						|
        // compiler generated code, with a million loops on x86-64:
 | 
						|
        //
 | 
						|
        // With "http": .10 vs .51 (first check)
 | 
						|
        // with "https": .16 vs .51 (second check)
 | 
						|
        // with "foo": .22 vs .31 (never found)
 | 
						|
        // with "mailto": .12 vs .51  (last check)
 | 
						|
        //
 | 
						|
        //
 | 
						|
        static bool IsPredefinedScheme(string scheme)
 | 
						|
        {
 | 
						|
            if (scheme == null || scheme.Length < 3)
 | 
						|
                return false;
 | 
						|
 | 
						|
            char c = scheme[0];
 | 
						|
            if (c == 'h')
 | 
						|
                return (scheme == "http" || scheme == "https");
 | 
						|
            if (c == 'f')
 | 
						|
                return (scheme == "file" || scheme == "ftp");
 | 
						|
 | 
						|
            if (c == 'n')
 | 
						|
            {
 | 
						|
                c = scheme[1];
 | 
						|
                if (c == 'e')
 | 
						|
                    return (scheme == "news" || scheme == "net.pipe" || scheme == "net.tcp");
 | 
						|
                if (scheme == "nntp")
 | 
						|
                    return true;
 | 
						|
                return false;
 | 
						|
            }
 | 
						|
            if ((c == 'g' && scheme == "gopher") || (c == 'm' && scheme == "mailto"))
 | 
						|
                return true;
 | 
						|
 | 
						|
            return false;
 | 
						|
        }
 | 
						|
 | 
						|
        internal static string Unquote(String str)
 | 
						|
        {
 | 
						|
            int start = str.IndexOf('\"');
 | 
						|
            int end = str.LastIndexOf('\"');
 | 
						|
            if (start >= 0 && end >= 0)
 | 
						|
                str = str.Substring(start + 1, end - 1);
 | 
						|
            return str.Trim();
 | 
						|
        }
 | 
						|
 | 
						|
        internal void AddHeader(string header)
 | 
						|
        {
 | 
						|
            int colon = header.IndexOf(':');
 | 
						|
            if (colon == -1 || colon == 0)
 | 
						|
            {
 | 
						|
                context.ErrorMessage = "Bad Request";
 | 
						|
                context.ErrorStatus = 400;
 | 
						|
                return;
 | 
						|
            }
 | 
						|
 | 
						|
            string name = header.Substring(0, colon).Trim();
 | 
						|
            string val = header.Substring(colon + 1).Trim();
 | 
						|
            string lower = name.ToLowerInvariant();
 | 
						|
            headers.SetInternal(name, val);
 | 
						|
            switch (lower)
 | 
						|
            {
 | 
						|
                case "accept-language":
 | 
						|
                    user_languages = val.Split(','); // yes, only split with a ','
 | 
						|
                    break;
 | 
						|
                case "accept":
 | 
						|
                    accept_types = val.Split(','); // yes, only split with a ','
 | 
						|
                    break;
 | 
						|
                case "content-length":
 | 
						|
                    try
 | 
						|
                    {
 | 
						|
                        //TODO: max. content_length?
 | 
						|
                        content_length = Int64.Parse(val.Trim());
 | 
						|
                        if (content_length < 0)
 | 
						|
                            context.ErrorMessage = "Invalid Content-Length.";
 | 
						|
                        cl_set = true;
 | 
						|
                    }
 | 
						|
                    catch
 | 
						|
                    {
 | 
						|
                        context.ErrorMessage = "Invalid Content-Length.";
 | 
						|
                    }
 | 
						|
 | 
						|
                    break;
 | 
						|
                case "content-type":
 | 
						|
                    {
 | 
						|
                        var contents = val.Split(';');
 | 
						|
                        foreach (var content in contents)
 | 
						|
                        {
 | 
						|
                            var tmp = content.Trim();
 | 
						|
                            if (tmp.StartsWith("charset"))
 | 
						|
                            {
 | 
						|
                                var charset = tmp.GetValue("=");
 | 
						|
                                if (charset != null && charset.Length > 0)
 | 
						|
                                {
 | 
						|
                                    try
 | 
						|
                                    {
 | 
						|
 | 
						|
                                        // Support upnp/dlna devices - CONTENT-TYPE: text/xml ; charset="utf-8"\r\n
 | 
						|
                                        charset = charset.Trim('"');
 | 
						|
                                        var index = charset.IndexOf('"');
 | 
						|
                                        if (index != -1) charset = charset.Substring(0, index);
 | 
						|
 | 
						|
                                        content_encoding = Encoding.GetEncoding(charset);
 | 
						|
                                    }
 | 
						|
                                    catch
 | 
						|
                                    {
 | 
						|
                                        context.ErrorMessage = "Invalid Content-Type header: " + charset;
 | 
						|
                                    }
 | 
						|
                                }
 | 
						|
 | 
						|
                                break;
 | 
						|
                            }
 | 
						|
                        }
 | 
						|
                    }
 | 
						|
                    break;
 | 
						|
                case "referer":
 | 
						|
                    try
 | 
						|
                    {
 | 
						|
                        referrer = new Uri(val);
 | 
						|
                    }
 | 
						|
                    catch
 | 
						|
                    {
 | 
						|
                        referrer = new Uri("http://someone.is.screwing.with.the.headers.com/");
 | 
						|
                    }
 | 
						|
                    break;
 | 
						|
                case "cookie":
 | 
						|
                    if (cookies == null)
 | 
						|
                        cookies = new CookieCollection();
 | 
						|
 | 
						|
                    string[] cookieStrings = val.Split(new char[] { ',', ';' });
 | 
						|
                    Cookie current = null;
 | 
						|
                    int version = 0;
 | 
						|
                    foreach (string cookieString in cookieStrings)
 | 
						|
                    {
 | 
						|
                        string str = cookieString.Trim();
 | 
						|
                        if (str.Length == 0)
 | 
						|
                            continue;
 | 
						|
                        if (str.StartsWith("$Version"))
 | 
						|
                        {
 | 
						|
                            version = Int32.Parse(Unquote(str.Substring(str.IndexOf('=') + 1)));
 | 
						|
                        }
 | 
						|
                        else if (str.StartsWith("$Path"))
 | 
						|
                        {
 | 
						|
                            if (current != null)
 | 
						|
                                current.Path = str.Substring(str.IndexOf('=') + 1).Trim();
 | 
						|
                        }
 | 
						|
                        else if (str.StartsWith("$Domain"))
 | 
						|
                        {
 | 
						|
                            if (current != null)
 | 
						|
                                current.Domain = str.Substring(str.IndexOf('=') + 1).Trim();
 | 
						|
                        }
 | 
						|
                        else if (str.StartsWith("$Port"))
 | 
						|
                        {
 | 
						|
                            if (current != null)
 | 
						|
                                current.Port = str.Substring(str.IndexOf('=') + 1).Trim();
 | 
						|
                        }
 | 
						|
                        else
 | 
						|
                        {
 | 
						|
                            if (current != null)
 | 
						|
                            {
 | 
						|
                                cookies.Add(current);
 | 
						|
                            }
 | 
						|
                            current = new Cookie();
 | 
						|
                            int idx = str.IndexOf('=');
 | 
						|
                            if (idx > 0)
 | 
						|
                            {
 | 
						|
                                current.Name = str.Substring(0, idx).Trim();
 | 
						|
                                current.Value = str.Substring(idx + 1).Trim();
 | 
						|
                            }
 | 
						|
                            else
 | 
						|
                            {
 | 
						|
                                current.Name = str.Trim();
 | 
						|
                                current.Value = String.Empty;
 | 
						|
                            }
 | 
						|
                            current.Version = version;
 | 
						|
                        }
 | 
						|
                    }
 | 
						|
                    if (current != null)
 | 
						|
                    {
 | 
						|
                        cookies.Add(current);
 | 
						|
                    }
 | 
						|
                    break;
 | 
						|
            }
 | 
						|
        }
 | 
						|
 | 
						|
        // returns true is the stream could be reused.
 | 
						|
        internal bool FlushInput()
 | 
						|
        {
 | 
						|
            if (!HasEntityBody)
 | 
						|
                return true;
 | 
						|
 | 
						|
            int length = 2048;
 | 
						|
            if (content_length > 0)
 | 
						|
                length = (int)Math.Min(content_length, (long)length);
 | 
						|
 | 
						|
            byte[] bytes = new byte[length];
 | 
						|
            while (true)
 | 
						|
            {
 | 
						|
                // TODO: test if MS has a timeout when doing this
 | 
						|
                try
 | 
						|
                {
 | 
						|
                    var task = InputStream.ReadAsync(bytes, 0, length);
 | 
						|
                    var result = Task.WaitAll(new [] { task }, 1000);
 | 
						|
                    if (!result)
 | 
						|
                    {
 | 
						|
                        return false;
 | 
						|
                    }
 | 
						|
                    if (task.Result <= 0)
 | 
						|
                    {
 | 
						|
                        return true;
 | 
						|
                    }
 | 
						|
                }
 | 
						|
                catch (ObjectDisposedException e)
 | 
						|
                {
 | 
						|
                    input_stream = null;
 | 
						|
                    return true;
 | 
						|
                }
 | 
						|
                catch
 | 
						|
                {
 | 
						|
                    return false;
 | 
						|
                }
 | 
						|
            }
 | 
						|
        }
 | 
						|
 | 
						|
        public string[] AcceptTypes
 | 
						|
        {
 | 
						|
            get { return accept_types; }
 | 
						|
        }
 | 
						|
 | 
						|
        public int ClientCertificateError
 | 
						|
        {
 | 
						|
            get
 | 
						|
            {
 | 
						|
                HttpConnection cnc = context.Connection;
 | 
						|
                //if (cnc.ClientCertificate == null)
 | 
						|
                //    throw new InvalidOperationException("No client certificate");
 | 
						|
                //int[] errors = cnc.ClientCertificateErrors;
 | 
						|
                //if (errors != null && errors.Length > 0)
 | 
						|
                //    return errors[0];
 | 
						|
                return 0;
 | 
						|
            }
 | 
						|
        }
 | 
						|
 | 
						|
        public Encoding ContentEncoding
 | 
						|
        {
 | 
						|
            get
 | 
						|
            {
 | 
						|
                if (content_encoding == null)
 | 
						|
                    content_encoding = _textEncoding.GetDefaultEncoding();
 | 
						|
                return content_encoding;
 | 
						|
            }
 | 
						|
        }
 | 
						|
 | 
						|
        public long ContentLength64
 | 
						|
        {
 | 
						|
            get { return is_chunked ? -1 : content_length; }
 | 
						|
        }
 | 
						|
 | 
						|
        public string ContentType
 | 
						|
        {
 | 
						|
            get { return headers["content-type"]; }
 | 
						|
        }
 | 
						|
 | 
						|
        public CookieCollection Cookies
 | 
						|
        {
 | 
						|
            get
 | 
						|
            {
 | 
						|
                // TODO: check if the collection is read-only
 | 
						|
                if (cookies == null)
 | 
						|
                    cookies = new CookieCollection();
 | 
						|
                return cookies;
 | 
						|
            }
 | 
						|
        }
 | 
						|
 | 
						|
        public bool HasEntityBody
 | 
						|
        {
 | 
						|
            get { return (content_length > 0 || is_chunked); }
 | 
						|
        }
 | 
						|
 | 
						|
        public QueryParamCollection Headers
 | 
						|
        {
 | 
						|
            get { return headers; }
 | 
						|
        }
 | 
						|
 | 
						|
        public string HttpMethod
 | 
						|
        {
 | 
						|
            get { return method; }
 | 
						|
        }
 | 
						|
 | 
						|
        public Stream InputStream
 | 
						|
        {
 | 
						|
            get
 | 
						|
            {
 | 
						|
                if (input_stream == null)
 | 
						|
                {
 | 
						|
                    if (is_chunked || content_length > 0)
 | 
						|
                        input_stream = context.Connection.GetRequestStream(is_chunked, content_length);
 | 
						|
                    else
 | 
						|
                        input_stream = Stream.Null;
 | 
						|
                }
 | 
						|
 | 
						|
                return input_stream;
 | 
						|
            }
 | 
						|
        }
 | 
						|
 | 
						|
        public bool IsAuthenticated
 | 
						|
        {
 | 
						|
            get { return false; }
 | 
						|
        }
 | 
						|
 | 
						|
        public bool IsLocal
 | 
						|
        {
 | 
						|
            get
 | 
						|
            {
 | 
						|
                var remoteEndPoint = RemoteEndPoint;
 | 
						|
 | 
						|
                return remoteEndPoint.Address.Equals(IPAddress.Loopback) ||
 | 
						|
                       remoteEndPoint.Address.Equals(IPAddress.IPv6Loopback) || 
 | 
						|
                        LocalEndPoint.Address.Equals(remoteEndPoint.Address);
 | 
						|
            }
 | 
						|
        }
 | 
						|
 | 
						|
        public bool IsSecureConnection
 | 
						|
        {
 | 
						|
            get { return context.Connection.IsSecure; }
 | 
						|
        }
 | 
						|
 | 
						|
        public bool KeepAlive
 | 
						|
        {
 | 
						|
            get
 | 
						|
            {
 | 
						|
                if (!_keepAlive.HasValue)
 | 
						|
                {
 | 
						|
                    string header = Headers["Proxy-Connection"];
 | 
						|
                    if (string.IsNullOrEmpty(header))
 | 
						|
                    {
 | 
						|
                        header = Headers["Connection"];
 | 
						|
                    }
 | 
						|
                    if (string.IsNullOrEmpty(header))
 | 
						|
                    {
 | 
						|
                        if (ProtocolVersion >= HttpVersion.Version11)
 | 
						|
                        {
 | 
						|
                            _keepAlive = true;
 | 
						|
                        }
 | 
						|
                        else
 | 
						|
                        {
 | 
						|
                            header = Headers["Keep-Alive"];
 | 
						|
                            _keepAlive = !string.IsNullOrEmpty(header);
 | 
						|
                        }
 | 
						|
                    }
 | 
						|
                    else
 | 
						|
                    {
 | 
						|
                        header = header.ToLower(CultureInfo.InvariantCulture);
 | 
						|
                        _keepAlive =
 | 
						|
                            header.IndexOf("close", StringComparison.OrdinalIgnoreCase) < 0 ||
 | 
						|
                            header.IndexOf("keep-alive", StringComparison.OrdinalIgnoreCase) >= 0;
 | 
						|
                    }
 | 
						|
                }
 | 
						|
 | 
						|
                return _keepAlive.Value;
 | 
						|
            }
 | 
						|
        }
 | 
						|
 | 
						|
        public IPEndPoint LocalEndPoint
 | 
						|
        {
 | 
						|
            get { return context.Connection.LocalEndPoint; }
 | 
						|
        }
 | 
						|
 | 
						|
        public Version ProtocolVersion
 | 
						|
        {
 | 
						|
            get { return version; }
 | 
						|
        }
 | 
						|
 | 
						|
        public QueryParamCollection QueryString
 | 
						|
        {
 | 
						|
            get { return query_string; }
 | 
						|
        }
 | 
						|
 | 
						|
        public string RawUrl
 | 
						|
        {
 | 
						|
            get { return raw_url; }
 | 
						|
        }
 | 
						|
 | 
						|
        public IPEndPoint RemoteEndPoint
 | 
						|
        {
 | 
						|
            get { return context.Connection.RemoteEndPoint; }
 | 
						|
        }
 | 
						|
 | 
						|
        public Guid RequestTraceIdentifier
 | 
						|
        {
 | 
						|
            get { return Guid.Empty; }
 | 
						|
        }
 | 
						|
 | 
						|
        public Uri Url
 | 
						|
        {
 | 
						|
            get { return url; }
 | 
						|
        }
 | 
						|
 | 
						|
        public Uri UrlReferrer
 | 
						|
        {
 | 
						|
            get { return referrer; }
 | 
						|
        }
 | 
						|
 | 
						|
        public string UserAgent
 | 
						|
        {
 | 
						|
            get { return headers["user-agent"]; }
 | 
						|
        }
 | 
						|
 | 
						|
        public string UserHostAddress
 | 
						|
        {
 | 
						|
            get { return LocalEndPoint.ToString(); }
 | 
						|
        }
 | 
						|
 | 
						|
        public string UserHostName
 | 
						|
        {
 | 
						|
            get { return headers["host"]; }
 | 
						|
        }
 | 
						|
 | 
						|
        public string[] UserLanguages
 | 
						|
        {
 | 
						|
            get { return user_languages; }
 | 
						|
        }
 | 
						|
 | 
						|
        public string ServiceName
 | 
						|
        {
 | 
						|
            get
 | 
						|
            {
 | 
						|
                return null;
 | 
						|
            }
 | 
						|
        }
 | 
						|
 | 
						|
        private bool _websocketRequestWasSet;
 | 
						|
        private bool _websocketRequest;
 | 
						|
 | 
						|
        /// <summary>
 | 
						|
        /// Gets a value indicating whether the request is a WebSocket connection request.
 | 
						|
        /// </summary>
 | 
						|
        /// <value>
 | 
						|
        /// <c>true</c> if the request is a WebSocket connection request; otherwise, <c>false</c>.
 | 
						|
        /// </value>
 | 
						|
        public bool IsWebSocketRequest
 | 
						|
        {
 | 
						|
            get
 | 
						|
            {
 | 
						|
                if (!_websocketRequestWasSet)
 | 
						|
                {
 | 
						|
                    _websocketRequest = method == "GET" &&
 | 
						|
                                        version > HttpVersion.Version10 &&
 | 
						|
                                        headers.Contains("Upgrade", "websocket") &&
 | 
						|
                                        headers.Contains("Connection", "Upgrade");
 | 
						|
 | 
						|
                    _websocketRequestWasSet = true;
 | 
						|
                }
 | 
						|
 | 
						|
                return _websocketRequest;
 | 
						|
            }
 | 
						|
        }
 | 
						|
    }
 | 
						|
}
 |