mirror of
https://github.com/nsnail/Ocelot.git
synced 2025-05-04 13:52:51 +08:00
130 lines
4.9 KiB
C#
130 lines
4.9 KiB
C#
using System.Threading.Tasks;
|
|
using Ocelot.DownstreamUrlCreator.UrlTemplateReplacer;
|
|
using Ocelot.Logging;
|
|
using Ocelot.Middleware;
|
|
using System;
|
|
using Ocelot.Responses;
|
|
using Ocelot.Values;
|
|
|
|
namespace Ocelot.DownstreamUrlCreator.Middleware
|
|
{
|
|
using System.Text.RegularExpressions;
|
|
|
|
public class DownstreamUrlCreatorMiddleware : OcelotMiddleware
|
|
{
|
|
private readonly OcelotRequestDelegate _next;
|
|
private readonly IDownstreamPathPlaceholderReplacer _replacer;
|
|
|
|
public DownstreamUrlCreatorMiddleware(OcelotRequestDelegate next,
|
|
IOcelotLoggerFactory loggerFactory,
|
|
IDownstreamPathPlaceholderReplacer replacer)
|
|
:base(loggerFactory.CreateLogger<DownstreamUrlCreatorMiddleware>())
|
|
{
|
|
_next = next;
|
|
_replacer = replacer;
|
|
}
|
|
|
|
public async Task Invoke(DownstreamContext context)
|
|
{
|
|
var response = _replacer
|
|
.Replace(context.DownstreamReRoute.DownstreamPathTemplate.Value, context.TemplatePlaceholderNameAndValues);
|
|
|
|
if (response.IsError)
|
|
{
|
|
Logger.LogDebug("IDownstreamPathPlaceholderReplacer returned an error, setting pipeline error");
|
|
|
|
SetPipelineError(context, response.Errors);
|
|
return;
|
|
}
|
|
|
|
context.DownstreamRequest.Scheme = context.DownstreamReRoute.DownstreamScheme;
|
|
|
|
if (ServiceFabricRequest(context))
|
|
{
|
|
var pathAndQuery = CreateServiceFabricUri(context, response);
|
|
context.DownstreamRequest.AbsolutePath = pathAndQuery.path;
|
|
context.DownstreamRequest.Query = pathAndQuery.query;
|
|
}
|
|
else
|
|
{
|
|
var dsPath = response.Data;
|
|
|
|
if(ContainsQueryString(dsPath))
|
|
{
|
|
context.DownstreamRequest.AbsolutePath = GetPath(dsPath);
|
|
|
|
if (string.IsNullOrEmpty(context.DownstreamRequest.Query))
|
|
{
|
|
context.DownstreamRequest.Query = GetQueryString(dsPath);
|
|
}
|
|
else
|
|
{
|
|
context.DownstreamRequest.Query += GetQueryString(dsPath).Replace('?', '&');
|
|
}
|
|
}
|
|
else
|
|
{
|
|
RemoveQueryStringParametersThatHaveBeenUsedInTemplate(context);
|
|
|
|
context.DownstreamRequest.AbsolutePath = dsPath.Value;
|
|
}
|
|
}
|
|
|
|
Logger.LogDebug($"Downstream url is {context.DownstreamRequest}");
|
|
|
|
await _next.Invoke(context);
|
|
}
|
|
|
|
private static void RemoveQueryStringParametersThatHaveBeenUsedInTemplate(DownstreamContext context)
|
|
{
|
|
foreach (var nAndV in context.TemplatePlaceholderNameAndValues)
|
|
{
|
|
var name = nAndV.Name.Replace("{", "").Replace("}", "");
|
|
|
|
if (context.DownstreamRequest.Query.Contains(name) &&
|
|
context.DownstreamRequest.Query.Contains(nAndV.Value))
|
|
{
|
|
var questionMarkOrAmpersand = context.DownstreamRequest.Query.IndexOf(name, StringComparison.Ordinal);
|
|
context.DownstreamRequest.Query = context.DownstreamRequest.Query.Remove(questionMarkOrAmpersand - 1, 1);
|
|
|
|
var rgx = new Regex($@"\b{name}={nAndV.Value}\b");
|
|
context.DownstreamRequest.Query = rgx.Replace(context.DownstreamRequest.Query, "");
|
|
|
|
if (!string.IsNullOrEmpty(context.DownstreamRequest.Query))
|
|
{
|
|
context.DownstreamRequest.Query = '?' + context.DownstreamRequest.Query.Substring(1);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
private string GetPath(DownstreamPath dsPath)
|
|
{
|
|
return dsPath.Value.Substring(0, dsPath.Value.IndexOf("?", StringComparison.Ordinal));
|
|
}
|
|
|
|
private string GetQueryString(DownstreamPath dsPath)
|
|
{
|
|
return dsPath.Value.Substring(dsPath.Value.IndexOf("?", StringComparison.Ordinal));
|
|
}
|
|
|
|
private bool ContainsQueryString(DownstreamPath dsPath)
|
|
{
|
|
return dsPath.Value.Contains("?");
|
|
}
|
|
|
|
private (string path, string query) CreateServiceFabricUri(DownstreamContext context, Response<DownstreamPath> dsPath)
|
|
{
|
|
var query = context.DownstreamRequest.Query;
|
|
var serviceName = _replacer.Replace(context.DownstreamReRoute.ServiceName, context.TemplatePlaceholderNameAndValues);
|
|
var pathTemplate = $"/{serviceName.Data.Value}{dsPath.Data.Value}";
|
|
return (pathTemplate, query);
|
|
}
|
|
|
|
private static bool ServiceFabricRequest(DownstreamContext context)
|
|
{
|
|
return context.Configuration.ServiceProviderConfiguration.Type?.ToLower() == "servicefabric" && context.DownstreamReRoute.UseServiceDiscovery;
|
|
}
|
|
}
|
|
}
|