public async Task AddResponseHeader_Success(string startValue, int status, string value, bool append, ResponseCondition condition, string expected, bool responseNull) { var httpContext = new DefaultHttpContext(); httpContext.Response.Headers["name"] = startValue.Split(";", System.StringSplitOptions.RemoveEmptyEntries); httpContext.Response.StatusCode = status; var transformContext = new ResponseTransformContext() { HttpContext = httpContext, ProxyResponse = responseNull ? null : new HttpResponseMessage(), HeadersCopied = true, }; var transform = new ResponseHeaderValueTransform("name", value, append, condition); await transform.ApplyAsync(transformContext); Assert.Equal(expected.Split(";", System.StringSplitOptions.RemoveEmptyEntries), httpContext.Response.Headers["name"]); }
/// <inheritdoc/> public Transforms Build(IList <IDictionary <string, string> > rawTransforms) { bool?copyRequestHeaders = null; bool?useOriginalHost = null; bool?forwardersSet = null; var requestTransforms = new List <RequestParametersTransform>(); var requestHeaderTransforms = new Dictionary <string, RequestHeaderTransform>(StringComparer.OrdinalIgnoreCase); var responseHeaderTransforms = new Dictionary <string, ResponseHeaderTransform>(StringComparer.OrdinalIgnoreCase); var responseTrailerTransforms = new Dictionary <string, ResponseHeaderTransform>(StringComparer.OrdinalIgnoreCase); if (rawTransforms?.Count > 0) { foreach (var rawTransform in rawTransforms) { if (rawTransform.TryGetValue("PathSet", out var pathSet)) { CheckTooManyParameters(rawTransform, expected: 1); var path = MakePathString(pathSet); requestTransforms.Add(new PathStringTransform(PathStringTransform.PathTransformMode.Set, path)); } else if (rawTransform.TryGetValue("PathPrefix", out var pathPrefix)) { CheckTooManyParameters(rawTransform, expected: 1); var path = MakePathString(pathPrefix); requestTransforms.Add(new PathStringTransform(PathStringTransform.PathTransformMode.Prefix, path)); } else if (rawTransform.TryGetValue("PathRemovePrefix", out var pathRemovePrefix)) { CheckTooManyParameters(rawTransform, expected: 1); var path = MakePathString(pathRemovePrefix); requestTransforms.Add(new PathStringTransform(PathStringTransform.PathTransformMode.RemovePrefix, path)); } else if (rawTransform.TryGetValue("PathPattern", out var pathPattern)) { CheckTooManyParameters(rawTransform, expected: 1); var path = MakePathString(pathPattern); requestTransforms.Add(new PathRouteValuesTransform(path.Value, _binderFactory)); } else if (rawTransform.TryGetValue("RequestHeadersCopy", out var copyHeaders)) { CheckTooManyParameters(rawTransform, expected: 1); copyRequestHeaders = string.Equals("True", copyHeaders, StringComparison.OrdinalIgnoreCase); } else if (rawTransform.TryGetValue("RequestHeaderOriginalHost", out var originalHost)) { CheckTooManyParameters(rawTransform, expected: 1); useOriginalHost = string.Equals("True", originalHost, StringComparison.OrdinalIgnoreCase); } else if (rawTransform.TryGetValue("RequestHeader", out var headerName)) { CheckTooManyParameters(rawTransform, expected: 2); if (rawTransform.TryGetValue("Set", out var setValue)) { // TODO: What about multiple transforms per header? Last wins? We don't have any examples for needing multiple. requestHeaderTransforms[headerName] = new RequestHeaderValueTransform(setValue, append: false); } else if (rawTransform.TryGetValue("Append", out var appendValue)) { requestHeaderTransforms[headerName] = new RequestHeaderValueTransform(appendValue, append: true); } else { throw new NotSupportedException(string.Join(';', rawTransform.Keys)); } } else if (rawTransform.TryGetValue("ResponseHeader", out var responseHeaderName)) { var always = false; if (rawTransform.TryGetValue("When", out var whenValue)) { CheckTooManyParameters(rawTransform, expected: 3); always = string.Equals("always", whenValue, StringComparison.OrdinalIgnoreCase); } else { CheckTooManyParameters(rawTransform, expected: 2); } if (rawTransform.TryGetValue("Set", out var setValue)) { responseHeaderTransforms[responseHeaderName] = new ResponseHeaderValueTransform(setValue, append: false, always); } else if (rawTransform.TryGetValue("Append", out var appendValue)) { responseHeaderTransforms[responseHeaderName] = new ResponseHeaderValueTransform(appendValue, append: true, always); } else { throw new NotSupportedException(string.Join(';', rawTransform.Keys)); } } else if (rawTransform.TryGetValue("ResponseTrailer", out var responseTrailerName)) { var always = false; if (rawTransform.TryGetValue("When", out var whenValue)) { CheckTooManyParameters(rawTransform, expected: 3); always = string.Equals("always", whenValue, StringComparison.OrdinalIgnoreCase); } else { CheckTooManyParameters(rawTransform, expected: 2); } if (rawTransform.TryGetValue("Set", out var setValue)) { responseTrailerTransforms[responseTrailerName] = new ResponseHeaderValueTransform(setValue, append: false, always); } else if (rawTransform.TryGetValue("Append", out var appendValue)) { responseTrailerTransforms[responseTrailerName] = new ResponseHeaderValueTransform(appendValue, append: true, always); } else { throw new NotSupportedException(string.Join(';', rawTransform.Keys)); } } else if (rawTransform.TryGetValue("X-Forwarded", out var xforwardedHeaders)) { forwardersSet = true; var expected = 1; var append = true; if (rawTransform.TryGetValue("Append", out var appendValue)) { expected++; append = string.Equals("true", appendValue, StringComparison.OrdinalIgnoreCase); } var prefix = "X-Forwarded-"; if (rawTransform.TryGetValue("Prefix", out var prefixValue)) { expected++; prefix = prefixValue; } CheckTooManyParameters(rawTransform, expected); // for, host, proto, PathBase var tokens = xforwardedHeaders.Split(new[] { ',', ' ' }, StringSplitOptions.RemoveEmptyEntries); foreach (var token in tokens) { if (string.Equals(token, "For", StringComparison.OrdinalIgnoreCase)) { requestHeaderTransforms[prefix + "For"] = new RequestHeaderXForwardedForTransform(append); } else if (string.Equals(token, "Host", StringComparison.OrdinalIgnoreCase)) { requestHeaderTransforms[prefix + "Host"] = new RequestHeaderXForwardedHostTransform(append); } else if (string.Equals(token, "Proto", StringComparison.OrdinalIgnoreCase)) { requestHeaderTransforms[prefix + "Proto"] = new RequestHeaderXForwardedProtoTransform(append); } else if (string.Equals(token, "PathBase", StringComparison.OrdinalIgnoreCase)) { requestHeaderTransforms[prefix + "PathBase"] = new RequestHeaderXForwardedPathBaseTransform(append); } else { throw new NotSupportedException(token); } } } else if (rawTransform.TryGetValue("Forwarded", out var forwardedHeader)) { forwardersSet = true; var useHost = false; var useProto = false; var useFor = false; var useBy = false; var forFormat = RequestHeaderForwardedTransform.NodeFormat.None; var byFormat = RequestHeaderForwardedTransform.NodeFormat.None; // for, host, proto, PathBase var tokens = forwardedHeader.Split(new[] { ',', ' ' }, StringSplitOptions.RemoveEmptyEntries); foreach (var token in tokens) { if (string.Equals(token, "For", StringComparison.OrdinalIgnoreCase)) { useFor = true; forFormat = RequestHeaderForwardedTransform.NodeFormat.Random; // RFC Default } else if (string.Equals(token, "By", StringComparison.OrdinalIgnoreCase)) { useBy = true; byFormat = RequestHeaderForwardedTransform.NodeFormat.Random; // RFC Default } else if (string.Equals(token, "Host", StringComparison.OrdinalIgnoreCase)) { useHost = true; } else if (string.Equals(token, "Proto", StringComparison.OrdinalIgnoreCase)) { useProto = true; } else { throw new NotSupportedException(token); } } var expected = 1; var append = true; if (rawTransform.TryGetValue("Append", out var appendValue)) { expected++; append = string.Equals("true", appendValue, StringComparison.OrdinalIgnoreCase); } if (useFor && rawTransform.TryGetValue("ForFormat", out var forFormatString)) { expected++; forFormat = Enum.Parse <RequestHeaderForwardedTransform.NodeFormat>(forFormatString, ignoreCase: true); } if (useBy && rawTransform.TryGetValue("ByFormat", out var byFormatString)) { expected++; byFormat = Enum.Parse <RequestHeaderForwardedTransform.NodeFormat>(byFormatString, ignoreCase: true); } CheckTooManyParameters(rawTransform, expected); if (useBy || useFor || useHost || useProto) { requestHeaderTransforms["Forwarded"] = new RequestHeaderForwardedTransform(_randomFactory, forFormat, byFormat, useHost, useProto, append); } } else if (rawTransform.TryGetValue("ClientCert", out var clientCertHeader)) { CheckTooManyParameters(rawTransform, expected: 1); requestHeaderTransforms[clientCertHeader] = new RequestHeaderClientCertTransform(); } else { throw new NotSupportedException(string.Join(';', rawTransform.Keys)); } } } // If there's no transform defined for Host, suppress the host by default if (!requestHeaderTransforms.ContainsKey(HeaderNames.Host) && !(useOriginalHost ?? false)) { requestHeaderTransforms[HeaderNames.Host] = new RequestHeaderValueTransform(string.Empty, append: false); } // Add default forwarders if (!forwardersSet.GetValueOrDefault()) { if (!requestHeaderTransforms.ContainsKey(ForwardedHeadersDefaults.XForwardedProtoHeaderName)) { requestHeaderTransforms[ForwardedHeadersDefaults.XForwardedProtoHeaderName] = new RequestHeaderXForwardedProtoTransform(append: true); } if (!requestHeaderTransforms.ContainsKey(ForwardedHeadersDefaults.XForwardedHostHeaderName)) { requestHeaderTransforms[ForwardedHeadersDefaults.XForwardedHostHeaderName] = new RequestHeaderXForwardedHostTransform(append: true); } if (!requestHeaderTransforms.ContainsKey(ForwardedHeadersDefaults.XForwardedForHeaderName)) { requestHeaderTransforms[ForwardedHeadersDefaults.XForwardedForHeaderName] = new RequestHeaderXForwardedForTransform(append: true); } if (!requestHeaderTransforms.ContainsKey("X-Forwarded-PathBase")) { requestHeaderTransforms["X-Forwarded-PathBase"] = new RequestHeaderXForwardedPathBaseTransform(append: true); } } return(new Transforms(copyRequestHeaders, requestTransforms, requestHeaderTransforms, responseHeaderTransforms, responseTrailerTransforms)); }