public async Task<IHttpRequest> Provide(IStreamReader reader)
        {
            // parse the http request
            var request = await reader.ReadLine().ConfigureAwait(false);

            if (request == null)
                return null;

            var firstSpace = request.IndexOf(' ');
            var lastSpace = request.LastIndexOf(' ');

            var tokens = new []
            {
                request.Substring(0, firstSpace),
                request.Substring(firstSpace + 1, lastSpace - firstSpace - 1),
                request.Substring(lastSpace + 1)
            };

            if (tokens.Length != 3)
            {
                return null;
            }

            
            var httpProtocol = tokens[2];

            var url = tokens[1];
            var queryString = GetQueryStringData(ref url);
            var uri = new Uri(url, UriKind.Relative);

            var headersRaw = new List<KeyValuePair<string, string>>();

            // get the headers
            string line;

            while (!string.IsNullOrEmpty((line = await reader.ReadLine().ConfigureAwait(false))))
            {
                string currentLine = line;

                var headerKvp = SplitHeader(currentLine);
                headersRaw.Add(headerKvp);
            }

            IHttpHeaders headers = new HttpHeaders(headersRaw.ToDictionary(k => k.Key, k => k.Value, StringComparer.InvariantCultureIgnoreCase));
            IHttpPost post = await GetPostData(reader, headers).ConfigureAwait(false);

            string verb;
            if (!headers.TryGetByName("_method", out verb))
            {
                verb = tokens[0];
            }
            var httpMethod = HttpMethodProvider.Default.Provide(verb);
            return new HttpRequest(headers, httpMethod, httpProtocol, uri,
                uri.OriginalString.Split(Separators, StringSplitOptions.RemoveEmptyEntries), queryString, post);
        }
        public QueryStringHttpHeaders(string query)
        {
            var splittedKeyValues = query.Split(Seperators, StringSplitOptions.RemoveEmptyEntries);
            var values = new Dictionary<string, string>(splittedKeyValues.Length / 2, StringComparer.InvariantCultureIgnoreCase);

            for (int i = 0; i < splittedKeyValues.Length; i += 2)
            {
                var key = Uri.UnescapeDataString(splittedKeyValues[i]);
                var value = Uri.UnescapeDataString(splittedKeyValues[i + 1]).Replace('+', ' ');

                values[key] = value;
            }

            _count = values.Count;
            _child = new HttpHeaders(values);
        }
        public async Task<IHttpRequest> Provide(HttpStreamReader streamReader)
        {
            // parse the http request
            var request = await streamReader.ReadLineAsync().ConfigureAwait(false);

            if (request == null)
                return null;

            var tokens = request.Split(' ');

            if (tokens.Length != 3)
            {
                return null;
            }

            var httpMethod = HttpMethodProvider.Default.Provide(tokens[0]);
            var httpProtocol = tokens[2];

            var url = tokens[1];
            var queryString = GetQueryStringData(ref url);
            var uri = new Uri(url, UriKind.Relative);

            var headersRaw = new Dictionary<string, string>(StringComparer.InvariantCultureIgnoreCase);

            // get the headers
            string line;
            while (!string.IsNullOrEmpty((line = await streamReader.ReadLineAsync().ConfigureAwait(false))))
            { 
                var headerKvp = SplitHeader(line);
                headersRaw.Add(headerKvp.Key, headerKvp.Value);
            }

            IHttpHeaders headers = new HttpHeaders(headersRaw);
            byte[] post = await GetPostData(streamReader, headers);

            return new HttpRequest(headers, httpMethod, httpProtocol, uri,
                uri.OriginalString.Split(Separators, StringSplitOptions.RemoveEmptyEntries), queryString, post);
        }