| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325 | using System;using System.IO;using System.Text;using MediaBrowser.Model.Services;namespace SocketHttpListener.Net{    public sealed partial class HttpListenerRequest    {        private long _contentLength;        private bool _clSet;        private WebHeaderCollection _headers;        private string _method;        private Stream _inputStream;        private HttpListenerContext _context;        private bool _isChunked;        private static byte[] s_100continue = Encoding.ASCII.GetBytes("HTTP/1.1 100 Continue\r\n\r\n");        internal HttpListenerRequest(HttpListenerContext context)        {            _context = context;            _headers = new WebHeaderCollection();            _version = HttpVersion.Version10;        }        private static readonly char[] s_separators = new char[] { ' ' };        internal void SetRequestLine(string req)        {            string[] parts = req.Split(s_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;            }            _rawUrl = 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));            }            catch            {                _context.ErrorMessage = "Invalid request line (version).";                return;            }            if (_version.Major < 1)            {                _context.ErrorMessage = "Invalid request line (version).";                return;            }            if (_version.Major > 1)            {                _context.ErrorStatus = (int)HttpStatusCode.HttpVersionNotSupported;                _context.ErrorMessage = HttpStatusDescription.Get(HttpStatusCode.HttpVersionNotSupported);                return;            }        }        private 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));        }        private static bool IsPredefinedScheme(string scheme)        {            if (scheme == null || scheme.Length < 3)                return false;            char c = scheme[0];            if (c == 'h')                return (scheme == UriScheme.Http || scheme == UriScheme.Https);            if (c == 'f')                return (scheme == UriScheme.File || scheme == UriScheme.Ftp);            if (c == 'n')            {                c = scheme[1];                if (c == 'e')                    return (scheme == UriScheme.News || scheme == UriScheme.NetPipe || scheme == UriScheme.NetTcp);                if (scheme == UriScheme.Nntp)                    return true;                return false;            }            if ((c == 'g' && scheme == UriScheme.Gopher) || (c == 'm' && scheme == UriScheme.Mailto))                return true;            return false;        }        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(_rawUrl.ToLowerInvariant()) && Uri.TryCreate(_rawUrl, UriKind.Absolute, out raw_uri))                path = raw_uri.PathAndQuery;            else                path = _rawUrl;            if ((host == null || host.Length == 0))                host = UserHostAddress;            if (raw_uri != null)                host = raw_uri.Host;            int colon = host.IndexOf(']') == -1 ? host.IndexOf(':') : host.LastIndexOf(':');            if (colon >= 0)                host = host.Substring(0, colon);            string base_uri = string.Format("{0}://{1}:{2}", RequestScheme, host, LocalEndPoint.Port);            if (!Uri.TryCreate(base_uri + path, UriKind.Absolute, out _requestUri))            {                _context.ErrorMessage = System.Net.WebUtility.HtmlEncode("Invalid url: " + base_uri + path);                return;            }            _requestUri = HttpListenerRequestUriBuilder.GetRequestUri(_rawUrl, _requestUri.Scheme,                                _requestUri.Authority, _requestUri.LocalPath, _requestUri.Query);            if (_version >= HttpVersion.Version11)            {                string t_encoding = Headers[HttpKnownHeaderNames.TransferEncoding];                _isChunked = (t_encoding != null && string.Equals(t_encoding, "chunked", StringComparison.OrdinalIgnoreCase));                // 'identity' is not valid!                if (t_encoding != null && !_isChunked)                {                    _context.Connection.SendError(null, 501);                    return;                }            }            if (!_isChunked && !_clSet)            {                if (string.Equals(_method, "POST", StringComparison.OrdinalIgnoreCase) ||                    string.Equals(_method, "PUT", StringComparison.OrdinalIgnoreCase))                {                    _context.Connection.SendError(null, 411);                    return;                }            }            if (string.Compare(Headers[HttpKnownHeaderNames.Expect], "100-continue", StringComparison.OrdinalIgnoreCase) == 0)            {                HttpResponseStream output = _context.Connection.GetResponseStream();                output.InternalWrite(s_100continue, 0, s_100continue.Length);            }        }        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 = HttpStatusDescription.Get(400);                _context.ErrorStatus = 400;                return;            }            string name = header.Substring(0, colon).Trim();            string val = header.Substring(colon + 1).Trim();            if (name.Equals("content-length", StringComparison.OrdinalIgnoreCase))            {                // To match Windows behavior:                // Content lengths >= 0 and <= long.MaxValue are accepted as is.                // Content lengths > long.MaxValue and <= ulong.MaxValue are treated as 0.                // Content lengths < 0 cause the requests to fail.                // Other input is a failure, too.                long parsedContentLength =                    ulong.TryParse(val, out ulong parsedUlongContentLength) ? (parsedUlongContentLength <= long.MaxValue ? (long)parsedUlongContentLength : 0) :                    long.Parse(val);                if (parsedContentLength < 0 || (_clSet && parsedContentLength != _contentLength))                {                    _context.ErrorMessage = "Invalid Content-Length.";                }                else                {                    _contentLength = parsedContentLength;                    _clSet = true;                }            }            else if (name.Equals("transfer-encoding", StringComparison.OrdinalIgnoreCase))            {                if (Headers[HttpKnownHeaderNames.TransferEncoding] != null)                {                    _context.ErrorStatus = (int)HttpStatusCode.NotImplemented;                    _context.ErrorMessage = HttpStatusDescription.Get(HttpStatusCode.NotImplemented);                }            }            if (_context.ErrorMessage == null)            {                _headers.Set(name, val);            }        }        // returns true is the stream could be reused.        internal bool FlushInput()        {            if (!HasEntityBody)                return true;            int length = 2048;            if (_contentLength > 0)                length = (int)Math.Min(_contentLength, (long)length);            byte[] bytes = new byte[length];            while (true)            {                try                {                    IAsyncResult ares = InputStream.BeginRead(bytes, 0, length, null, null);                    if (!ares.IsCompleted && !ares.AsyncWaitHandle.WaitOne(1000))                        return false;                    if (InputStream.EndRead(ares) <= 0)                        return true;                }                catch (ObjectDisposedException)                {                    _inputStream = null;                    return true;                }                catch                {                    return false;                }            }        }        public long ContentLength64        {            get            {                if (_isChunked)                    _contentLength = -1;                return _contentLength;            }        }        public bool HasEntityBody => (_contentLength > 0 || _isChunked);        public QueryParamCollection Headers => _headers;        public string HttpMethod => _method;        public Stream InputStream        {            get            {                if (_inputStream == null)                {                    if (_isChunked || _contentLength > 0)                        _inputStream = _context.Connection.GetRequestStream(_isChunked, _contentLength);                    else                        _inputStream = Stream.Null;                }                return _inputStream;            }        }        public bool IsAuthenticated => false;        public bool IsSecureConnection => _context.Connection.IsSecure;        public System.Net.IPEndPoint LocalEndPoint => _context.Connection.LocalEndPoint;        public System.Net.IPEndPoint RemoteEndPoint => _context.Connection.RemoteEndPoint;        public Guid RequestTraceIdentifier { get; } = Guid.NewGuid();        public string ServiceName => null;        private Uri RequestUri => _requestUri;        private bool SupportsWebSockets => true;    }}
 |