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; }