private static bool CheckRequiredCallData(IDictionary<string, object> env, IList<string> warnings)
        {
            var req = new Request(env);
            string[] requiredKeys = new string[]
            {
                "owin.Version",
                "owin.CallCancelled",

                "owin.RequestBody",
                "owin.RequestHeaders",
                "owin.RequestMethod",
                "owin.RequestPath",
                "owin.RequestPathBase",
                "owin.RequestProtocol",
                "owin.RequestQueryString",
                "owin.RequestScheme",

                "owin.ResponseHeaders",
                "owin.ResponseBody",
            };

            object temp;
            foreach (string key in requiredKeys)
            {
                if (!env.TryGetValue(key, out temp))
                {
                    SetFatalResult(env, "3.2", "Missing required Environment key: " + key);
                    return false;
                }

                if (temp == null)
                {
                    SetFatalResult(env, "3.2", "Required Environment value is null: " + key);
                    return false;
                }
            }

            IDictionary<string, string[]> requestHeaders = req.Get<IDictionary<string, string[]>>("owin.RequestHeaders");
            IDictionary<string, string[]> responseHeaders = req.Get<IDictionary<string, string[]>>("owin.ResponseHeaders");

            if (!TryValidateHeaderCollection(env, requestHeaders, "Request", warnings))
            {
                return false;
            }

            if (!TryValidateHeaderCollection(env, responseHeaders, "Response", warnings))
            {
                return false;
            }

            string[] header;
            if (!requestHeaders.TryGetValue("HOST", out header) || header.Length == 0)
            {
                SetFatalResult(env, "5.2", "Missing Host header");
                return false;
            }

            // Validate values

            string[] stringValueTypes = new string[]
            {
                "owin.RequestMethod",
                "owin.RequestPath",
                "owin.RequestPathBase",
                "owin.RequestProtocol",
                "owin.RequestQueryString",
                "owin.RequestScheme",
                "owin.Version" 
            };

            foreach (string key in stringValueTypes)
            {
                if (!(env[key] is string))
                {
                    SetFatalResult(env, "3.2", key + " value is not of type string: " + env[key].GetType().FullName);
                    return false;
                }
            }

            if (!(env["owin.CallCancelled"] is CancellationToken))
            {
                SetFatalResult(env, "3.2.3", "owin.CallCancelled is not of type CancellationToken: " + env["owin.CallCancelled"].GetType().FullName);
                return false;
            }

            if (req.Get<CancellationToken>("owin.CallCancelled").IsCancellationRequested)
            {
                warnings.Add(CreateWarning("3.6", "The owin.CallCancelled CancellationToken was cancelled before processing the request."));
            }

            if (string.IsNullOrWhiteSpace(req.Get<string>("owin.RequestMethod")))
            {
                SetFatalResult(env, "3.2.1", "owin.RequestMethod is empty.");
                return false;
            }

            string pathBase = req.Get<string>("owin.RequestPathBase");
            if (pathBase.EndsWith("/"))
            {
                SetFatalResult(env, "5.3", "owin.RequestBasePath ends with a slash: " + pathBase);
                return false;
            }


            if (!(pathBase.StartsWith("/") || pathBase.Equals(string.Empty)))
            {
                SetFatalResult(env, "5.3", "owin.RequestBasePath is not empty and does not start with a slash: " + pathBase);
                return false;
            }

            string path = req.Get<string>("owin.RequestPath");
            if (!path.StartsWith("/"))
            {
                if (path.Equals(string.Empty))
                {
                    if (pathBase.Equals(string.Empty))
                    {
                        SetFatalResult(env, "5.3", "owin.RequestPathBase and owin.RequestPath are both empty.");
                        return false;
                    }
                }
                else
                {
                    SetFatalResult(env, "5.3", "owin.RequestPath does not start with a slash.");
                    return false;
                }
            }

            string protocol = req.Get<string>("owin.RequestProtocol");
            if (!protocol.Equals("HTTP/1.1", StringComparison.OrdinalIgnoreCase)
                && !protocol.Equals("HTTP/1.0", StringComparison.OrdinalIgnoreCase))
            {
                warnings.Add(CreateWarning("3.2.1", "Unrecognized request protocol: " + protocol));
            }

            // No query string validation.

            string scheme = req.Get<string>("owin.RequestScheme");
            if (!scheme.Equals("http", StringComparison.OrdinalIgnoreCase)
                && !scheme.Equals("https", StringComparison.OrdinalIgnoreCase))
            {
                warnings.Add(CreateWarning("5.1", "Unrecognized request scheme: " + scheme));
            }

            string version = req.Get<string>("owin.Version");
            Version parsedVersion;
            if (!Version.TryParse(version, out parsedVersion))
            {
                SetFatalResult(env, "7", "owin.Version could not be parsed: " + version);
                return false;
            }

            if (!parsedVersion.Equals(new Version(1, 0)))
            {
                warnings.Add(CreateWarning("7", "Unrecognized OWIN version: " + version));
            }

            return true;
        }
        // Returns false for fatal errors, along with a resulting message.
        // Otherwise any warnings are appended.
        private static bool TryValidateCall(IDictionary<string, object> env, IList<string> warnings)
        {
            if (env == null)
            {
                throw new ArgumentNullException("env");
            }

            var req = new Request(env);

            // Must be mutable
            try
            {
                string key = "validator.MutableKey";
                string input = "Mutable Value";
                req.Set(key, input);
                string output = req.Get<string>(key);
                if (output == null || output != input)
                {
                    SetFatalResult(env, "3.2", "Environment is not fully mutable.");
                    return false;
                }
                req.Set<string>(key, null);
            }
            catch (Exception ex)
            {
                SetFatalResult(env, "3.2", "Environment is not mutable: \r\n" + ex.ToString());
                return false;
            }

            // Environment key names MUST be case sensitive.
            string upperKey = "Validator.CaseKey";
            string lowerKey = "validator.casekey";
            string[] caseValue = new string[] { "Case Value" };
            env[upperKey] = caseValue;
            string[] resultValue = req.Get<string[]>(lowerKey);
            if (resultValue != null)
            {
                SetFatalResult(env, "3.2", "Environment is not case sensitive.");
                return false;
            }
            env.Remove(upperKey);

            // Check for required owin.* keys and the HOST header.
            if (!CheckRequiredCallData(env, warnings))
            {
                return false;
            }

            return true;
        }