everything working..now for the docs

This commit is contained in:
Tom Pallister 2017-11-01 15:51:49 +00:00
commit f4e8dcbdab
34 changed files with 1242 additions and 809 deletions

View File

@ -1,6 +1,7 @@
#tool "nuget:?package=GitVersion.CommandLine" #tool "nuget:?package=GitVersion.CommandLine"
#tool "nuget:?package=GitReleaseNotes" #tool "nuget:?package=GitReleaseNotes"
#addin "nuget:?package=Cake.Json" #addin nuget:?package=Cake.Json
#addin nuget:?package=Newtonsoft.Json&version=9.0.1
#tool "nuget:?package=OpenCover" #tool "nuget:?package=OpenCover"
#tool "nuget:?package=ReportGenerator" #tool "nuget:?package=ReportGenerator"
#tool coveralls.net #tool coveralls.net
@ -260,11 +261,19 @@ Task("ReleasePackagesToUnstableFeed")
Task("EnsureStableReleaseRequirements") Task("EnsureStableReleaseRequirements")
.Does(() => .Does(() =>
{ {
Information("Check if stable release...");
if (!AppVeyor.IsRunningOnAppVeyor) if (!AppVeyor.IsRunningOnAppVeyor)
{ {
throw new Exception("Stable release should happen via appveyor"); throw new Exception("Stable release should happen via appveyor");
} }
Information("Running on AppVeyor...");
Information("IsTag = " + AppVeyor.Environment.Repository.Tag.IsTag);
Information("Name = " + AppVeyor.Environment.Repository.Tag.Name);
var isTag = var isTag =
AppVeyor.Environment.Repository.Tag.IsTag && AppVeyor.Environment.Repository.Tag.IsTag &&
!string.IsNullOrWhiteSpace(AppVeyor.Environment.Repository.Tag.Name); !string.IsNullOrWhiteSpace(AppVeyor.Environment.Repository.Tag.Name);
@ -273,6 +282,8 @@ Task("EnsureStableReleaseRequirements")
{ {
throw new Exception("Stable release should happen from a published GitHub release"); throw new Exception("Stable release should happen from a published GitHub release");
} }
Information("Release is stable...");
}); });
Task("UpdateVersionInfo") Task("UpdateVersionInfo")
@ -287,19 +298,48 @@ Task("DownloadGitHubReleaseArtifacts")
.IsDependentOn("UpdateVersionInfo") .IsDependentOn("UpdateVersionInfo")
.Does(() => .Does(() =>
{ {
EnsureDirectoryExists(packagesDir); try
{
Information("DownloadGitHubReleaseArtifacts");
var releaseUrl = tagsUrl + releaseTag; EnsureDirectoryExists(packagesDir);
var assets_url = ParseJson(GetResource(releaseUrl))
.GetValue("assets_url")
.Value<string>();
foreach(var asset in DeserializeJson<JArray>(GetResource(assets_url))) Information("Directory exists...");
{
var file = packagesDir + File(asset.Value<string>("name")); var releaseUrl = tagsUrl + releaseTag;
Information("Downloading " + file);
DownloadFile(asset.Value<string>("browser_download_url"), file); Information("Release url " + releaseUrl);
}
//var releaseJson = Newtonsoft.Json.Linq.JObject.Parse(GetResource(releaseUrl));
var assets_url = Newtonsoft.Json.Linq.JObject.Parse(GetResource(releaseUrl))
.GetValue("assets_url")
.Value<string>();
Information("Assets url " + assets_url);
var assets = GetResource(assets_url);
Information("Assets " + assets_url);
foreach(var asset in Newtonsoft.Json.JsonConvert.DeserializeObject<JArray>(assets))
{
Information("In the loop..");
var file = packagesDir + File(asset.Value<string>("name"));
Information("Downloading " + file);
DownloadFile(asset.Value<string>("browser_download_url"), file);
}
Information("Out of the loop...");
}
catch(Exception exception)
{
Information("There was an exception " + exception);
throw;
}
}); });
Task("ReleasePackagesToStableFeed") Task("ReleasePackagesToStableFeed")
@ -394,19 +434,31 @@ private void PublishPackages(ConvertableDirectoryPath packagesDir, ConvertableFi
/// gets the resource from the specified url /// gets the resource from the specified url
private string GetResource(string url) private string GetResource(string url)
{ {
Information("Getting resource from " + url); try
{
Information("Getting resource from " + url);
var assetsRequest = System.Net.WebRequest.CreateHttp(url); var assetsRequest = System.Net.WebRequest.CreateHttp(url);
assetsRequest.Method = "GET"; assetsRequest.Method = "GET";
assetsRequest.Accept = "application/vnd.github.v3+json"; assetsRequest.Accept = "application/vnd.github.v3+json";
assetsRequest.UserAgent = "BuildScript"; assetsRequest.UserAgent = "BuildScript";
using (var assetsResponse = assetsRequest.GetResponse()) using (var assetsResponse = assetsRequest.GetResponse())
{ {
var assetsStream = assetsResponse.GetResponseStream(); var assetsStream = assetsResponse.GetResponseStream();
var assetsReader = new StreamReader(assetsStream); var assetsReader = new StreamReader(assetsStream);
return assetsReader.ReadToEnd(); var response = assetsReader.ReadToEnd();
}
Information("Response is " + response);
return response;
}
}
catch(Exception exception)
{
Information("There was an exception " + exception);
throw;
}
} }
private bool ShouldPublishToUnstableFeed(string filter, string branchName) private bool ShouldPublishToUnstableFeed(string filter, string branchName)

117
build.ps1
View File

@ -21,34 +21,35 @@ The build script target to run.
The build configuration to use. The build configuration to use.
.PARAMETER Verbosity .PARAMETER Verbosity
Specifies the amount of information to be displayed. Specifies the amount of information to be displayed.
.PARAMETER ShowDescription
Shows description about tasks.
.PARAMETER DryRun
Performs a dry run.
.PARAMETER Experimental .PARAMETER Experimental
Tells Cake to use the latest Roslyn release. Uses the nightly builds of the Roslyn script engine.
.PARAMETER WhatIf
Performs a dry run of the build script.
No tasks will be executed.
.PARAMETER Mono .PARAMETER Mono
Tells Cake to use the Mono scripting engine. Uses the Mono Compiler rather than the Roslyn script engine.
.PARAMETER SkipToolPackageRestore .PARAMETER SkipToolPackageRestore
Skips restoring of packages. Skips restoring of packages.
.PARAMETER ScriptArgs .PARAMETER ScriptArgs
Remaining arguments are added here. Remaining arguments are added here.
.LINK .LINK
http://cakebuild.net https://cakebuild.net
#> #>
[CmdletBinding()] [CmdletBinding()]
Param( Param(
[string]$Script = "build.cake", [string]$Script = "build.cake",
[string]$Target = "Default", [string]$Target,
[ValidateSet("Release", "Debug")] [string]$Configuration,
[string]$Configuration = "Release",
[ValidateSet("Quiet", "Minimal", "Normal", "Verbose", "Diagnostic")] [ValidateSet("Quiet", "Minimal", "Normal", "Verbose", "Diagnostic")]
[string]$Verbosity = "Verbose", [string]$Verbosity,
[switch]$ShowDescription,
[Alias("WhatIf", "Noop")]
[switch]$DryRun,
[switch]$Experimental, [switch]$Experimental,
[Alias("DryRun","Noop")]
[switch]$WhatIf,
[switch]$Mono, [switch]$Mono,
[switch]$SkipToolPackageRestore, [switch]$SkipToolPackageRestore,
[Parameter(Position=0,Mandatory=$false,ValueFromRemainingArguments=$true)] [Parameter(Position=0,Mandatory=$false,ValueFromRemainingArguments=$true)]
@ -80,6 +81,15 @@ function MD5HashFile([string] $filePath)
} }
} }
function GetProxyEnabledWebClient
{
$wc = New-Object System.Net.WebClient
$proxy = [System.Net.WebRequest]::GetSystemWebProxy()
$proxy.Credentials = [System.Net.CredentialCache]::DefaultCredentials
$wc.Proxy = $proxy
return $wc
}
Write-Host "Preparing to run build script..." Write-Host "Preparing to run build script..."
if(!$PSScriptRoot){ if(!$PSScriptRoot){
@ -87,31 +97,15 @@ if(!$PSScriptRoot){
} }
$TOOLS_DIR = Join-Path $PSScriptRoot "tools" $TOOLS_DIR = Join-Path $PSScriptRoot "tools"
$ADDINS_DIR = Join-Path $TOOLS_DIR "Addins"
$MODULES_DIR = Join-Path $TOOLS_DIR "Modules"
$NUGET_EXE = Join-Path $TOOLS_DIR "nuget.exe" $NUGET_EXE = Join-Path $TOOLS_DIR "nuget.exe"
$CAKE_EXE = Join-Path $TOOLS_DIR "Cake/Cake.exe" $CAKE_EXE = Join-Path $TOOLS_DIR "Cake/Cake.exe"
$NUGET_URL = "https://dist.nuget.org/win-x86-commandline/latest/nuget.exe" $NUGET_URL = "https://dist.nuget.org/win-x86-commandline/latest/nuget.exe"
$PACKAGES_CONFIG = Join-Path $TOOLS_DIR "packages.config" $PACKAGES_CONFIG = Join-Path $TOOLS_DIR "packages.config"
$PACKAGES_CONFIG_MD5 = Join-Path $TOOLS_DIR "packages.config.md5sum" $PACKAGES_CONFIG_MD5 = Join-Path $TOOLS_DIR "packages.config.md5sum"
$ADDINS_PACKAGES_CONFIG = Join-Path $ADDINS_DIR "packages.config"
# Should we use mono? $MODULES_PACKAGES_CONFIG = Join-Path $MODULES_DIR "packages.config"
$UseMono = "";
if($Mono.IsPresent) {
Write-Verbose -Message "Using the Mono based scripting engine."
$UseMono = "-mono"
}
# Should we use the new Roslyn?
$UseExperimental = "";
if($Experimental.IsPresent -and !($Mono.IsPresent)) {
Write-Verbose -Message "Using experimental version of Roslyn."
$UseExperimental = "-experimental"
}
# Is this a dry run?
$UseDryRun = "";
if($WhatIf.IsPresent) {
$UseDryRun = "-dryrun"
}
# Make sure tools folder exists # Make sure tools folder exists
if ((Test-Path $PSScriptRoot) -and !(Test-Path $TOOLS_DIR)) { if ((Test-Path $PSScriptRoot) -and !(Test-Path $TOOLS_DIR)) {
@ -122,7 +116,9 @@ if ((Test-Path $PSScriptRoot) -and !(Test-Path $TOOLS_DIR)) {
# Make sure that packages.config exist. # Make sure that packages.config exist.
if (!(Test-Path $PACKAGES_CONFIG)) { if (!(Test-Path $PACKAGES_CONFIG)) {
Write-Verbose -Message "Downloading packages.config..." Write-Verbose -Message "Downloading packages.config..."
try { (New-Object System.Net.WebClient).DownloadFile("http://cakebuild.net/download/bootstrapper/packages", $PACKAGES_CONFIG) } catch { try {
$wc = GetProxyEnabledWebClient
$wc.DownloadFile("https://cakebuild.net/download/bootstrapper/packages", $PACKAGES_CONFIG) } catch {
Throw "Could not download packages.config." Throw "Could not download packages.config."
} }
} }
@ -130,7 +126,7 @@ if (!(Test-Path $PACKAGES_CONFIG)) {
# Try find NuGet.exe in path if not exists # Try find NuGet.exe in path if not exists
if (!(Test-Path $NUGET_EXE)) { if (!(Test-Path $NUGET_EXE)) {
Write-Verbose -Message "Trying to find nuget.exe in PATH..." Write-Verbose -Message "Trying to find nuget.exe in PATH..."
$existingPaths = $Env:Path -Split ';' | Where-Object { (![string]::IsNullOrEmpty($_)) -and (Test-Path $_) } $existingPaths = $Env:Path -Split ';' | Where-Object { (![string]::IsNullOrEmpty($_)) -and (Test-Path $_ -PathType Container) }
$NUGET_EXE_IN_PATH = Get-ChildItem -Path $existingPaths -Filter "nuget.exe" | Select -First 1 $NUGET_EXE_IN_PATH = Get-ChildItem -Path $existingPaths -Filter "nuget.exe" | Select -First 1
if ($NUGET_EXE_IN_PATH -ne $null -and (Test-Path $NUGET_EXE_IN_PATH.FullName)) { if ($NUGET_EXE_IN_PATH -ne $null -and (Test-Path $NUGET_EXE_IN_PATH.FullName)) {
Write-Verbose -Message "Found in PATH at $($NUGET_EXE_IN_PATH.FullName)." Write-Verbose -Message "Found in PATH at $($NUGET_EXE_IN_PATH.FullName)."
@ -142,7 +138,8 @@ if (!(Test-Path $NUGET_EXE)) {
if (!(Test-Path $NUGET_EXE)) { if (!(Test-Path $NUGET_EXE)) {
Write-Verbose -Message "Downloading NuGet.exe..." Write-Verbose -Message "Downloading NuGet.exe..."
try { try {
(New-Object System.Net.WebClient).DownloadFile($NUGET_URL, $NUGET_EXE) $wc = GetProxyEnabledWebClient
$wc.DownloadFile($NUGET_URL, $NUGET_EXE)
} catch { } catch {
Throw "Could not download NuGet.exe." Throw "Could not download NuGet.exe."
} }
@ -175,6 +172,41 @@ if(-Not $SkipToolPackageRestore.IsPresent) {
$md5Hash | Out-File $PACKAGES_CONFIG_MD5 -Encoding "ASCII" $md5Hash | Out-File $PACKAGES_CONFIG_MD5 -Encoding "ASCII"
} }
Write-Verbose -Message ($NuGetOutput | out-string) Write-Verbose -Message ($NuGetOutput | out-string)
Pop-Location
}
# Restore addins from NuGet
if (Test-Path $ADDINS_PACKAGES_CONFIG) {
Push-Location
Set-Location $ADDINS_DIR
Write-Verbose -Message "Restoring addins from NuGet..."
$NuGetOutput = Invoke-Expression "&`"$NUGET_EXE`" install -ExcludeVersion -OutputDirectory `"$ADDINS_DIR`""
if ($LASTEXITCODE -ne 0) {
Throw "An error occured while restoring NuGet addins."
}
Write-Verbose -Message ($NuGetOutput | out-string)
Pop-Location
}
# Restore modules from NuGet
if (Test-Path $MODULES_PACKAGES_CONFIG) {
Push-Location
Set-Location $MODULES_DIR
Write-Verbose -Message "Restoring modules from NuGet..."
$NuGetOutput = Invoke-Expression "&`"$NUGET_EXE`" install -ExcludeVersion -OutputDirectory `"$MODULES_DIR`""
if ($LASTEXITCODE -ne 0) {
Throw "An error occured while restoring NuGet modules."
}
Write-Verbose -Message ($NuGetOutput | out-string)
Pop-Location Pop-Location
} }
@ -183,7 +215,20 @@ if (!(Test-Path $CAKE_EXE)) {
Throw "Could not find Cake.exe at $CAKE_EXE" Throw "Could not find Cake.exe at $CAKE_EXE"
} }
# Build Cake arguments
$cakeArguments = @("$Script");
if ($Target) { $cakeArguments += "-target=$Target" }
if ($Configuration) { $cakeArguments += "-configuration=$Configuration" }
if ($Verbosity) { $cakeArguments += "-verbosity=$Verbosity" }
if ($ShowDescription) { $cakeArguments += "-showdescription" }
if ($DryRun) { $cakeArguments += "-dryrun" }
if ($Experimental) { $cakeArguments += "-experimental" }
if ($Mono) { $cakeArguments += "-mono" }
$cakeArguments += $ScriptArgs
# Start Cake # Start Cake
Write-Host "Running build script..." Write-Host "Running build script..."
Invoke-Expression "& `"$CAKE_EXE`" `"$Script`" -target=`"$Target`" -configuration=`"$Configuration`" -verbosity=`"$Verbosity`" $UseMono $UseDryRun $UseExperimental $ScriptArgs" &$CAKE_EXE $cakeArguments
exit $LASTEXITCODE exit $LASTEXITCODE

View File

@ -36,7 +36,7 @@ namespace Ocelot.Authentication.Middleware
{ {
_logger.LogDebug($"{context.Request.Path} is an authenticated route. {MiddlewareName} checking if client is authenticated"); _logger.LogDebug($"{context.Request.Path} is an authenticated route. {MiddlewareName} checking if client is authenticated");
var result = await context.AuthenticateAsync(DownstreamRoute.ReRoute.AuthenticationProviderKey); var result = await context.AuthenticateAsync(DownstreamRoute.ReRoute.AuthenticationOptions.AuthenticationProviderKey);
context.User = result.Principal; context.User = result.Principal;

View File

@ -4,11 +4,13 @@ namespace Ocelot.Configuration
{ {
public class AuthenticationOptions public class AuthenticationOptions
{ {
public AuthenticationOptions(List<string> allowedScopes) public AuthenticationOptions(List<string> allowedScopes, string authenticationProviderKey)
{ {
AllowedScopes = allowedScopes; AllowedScopes = allowedScopes;
AuthenticationProviderKey = authenticationProviderKey;
} }
public List<string> AllowedScopes { get; private set; } public List<string> AllowedScopes { get; private set; }
public string AuthenticationProviderKey { get; private set; }
} }
} }

View File

@ -5,6 +5,7 @@ namespace Ocelot.Configuration.Builder
public class AuthenticationOptionsBuilder public class AuthenticationOptionsBuilder
{ {
private List<string> _allowedScopes = new List<string>(); private List<string> _allowedScopes = new List<string>();
private string _authenticationProviderKey;
public AuthenticationOptionsBuilder WithAllowedScopes(List<string> allowedScopes) public AuthenticationOptionsBuilder WithAllowedScopes(List<string> allowedScopes)
{ {
@ -12,9 +13,15 @@ namespace Ocelot.Configuration.Builder
return this; return this;
} }
public AuthenticationOptionsBuilder WithAuthenticationProviderKey(string authenticationProviderKey)
{
_authenticationProviderKey = authenticationProviderKey;
return this;
}
public AuthenticationOptions Build() public AuthenticationOptions Build()
{ {
return new AuthenticationOptions(_allowedScopes); return new AuthenticationOptions(_allowedScopes, _authenticationProviderKey);
} }
} }
} }

View File

@ -29,6 +29,7 @@ namespace Ocelot.Configuration.Builder
private ServiceProviderConfiguration _serviceProviderConfiguraion; private ServiceProviderConfiguration _serviceProviderConfiguraion;
private bool _useQos; private bool _useQos;
private QoSOptions _qosOptions; private QoSOptions _qosOptions;
private HttpHandlerOptions _httpHandlerOptions;
public bool _enableRateLimiting; public bool _enableRateLimiting;
public RateLimitOptions _rateLimitOptions; public RateLimitOptions _rateLimitOptions;
private string _authenticationProviderKey; private string _authenticationProviderKey;
@ -183,6 +184,11 @@ namespace Ocelot.Configuration.Builder
return this; return this;
} }
public ReRouteBuilder WithHttpHandlerOptions(HttpHandlerOptions input)
{
_httpHandlerOptions = input;
return this;
}
public ReRoute Build() public ReRoute Build()
{ {
@ -211,7 +217,7 @@ namespace Ocelot.Configuration.Builder
_qosOptions, _qosOptions,
_enableRateLimiting, _enableRateLimiting,
_rateLimitOptions, _rateLimitOptions,
_authenticationProviderKey); _httpHandlerOptions);
} }
} }
} }

View File

@ -6,7 +6,7 @@ namespace Ocelot.Configuration.Creator
{ {
public AuthenticationOptions Create(FileReRoute reRoute) public AuthenticationOptions Create(FileReRoute reRoute)
{ {
return new AuthenticationOptions(reRoute.AuthenticationOptions.AllowedScopes); return new AuthenticationOptions(reRoute.AuthenticationOptions.AllowedScopes, reRoute.AuthenticationOptions.AuthenticationProviderKey);
} }
} }
} }

View File

@ -38,6 +38,7 @@ namespace Ocelot.Configuration.Creator
private readonly IReRouteOptionsCreator _fileReRouteOptionsCreator; private readonly IReRouteOptionsCreator _fileReRouteOptionsCreator;
private readonly IRateLimitOptionsCreator _rateLimitOptionsCreator; private readonly IRateLimitOptionsCreator _rateLimitOptionsCreator;
private readonly IRegionCreator _regionCreator; private readonly IRegionCreator _regionCreator;
private readonly IHttpHandlerOptionsCreator _httpHandlerOptionsCreator;
public FileOcelotConfigurationCreator( public FileOcelotConfigurationCreator(
IOptions<FileConfiguration> options, IOptions<FileConfiguration> options,
@ -55,7 +56,8 @@ namespace Ocelot.Configuration.Creator
IQoSOptionsCreator qosOptionsCreator, IQoSOptionsCreator qosOptionsCreator,
IReRouteOptionsCreator fileReRouteOptionsCreator, IReRouteOptionsCreator fileReRouteOptionsCreator,
IRateLimitOptionsCreator rateLimitOptionsCreator, IRateLimitOptionsCreator rateLimitOptionsCreator,
IRegionCreator regionCreator IRegionCreator regionCreator,
IHttpHandlerOptionsCreator httpHandlerOptionsCreator
) )
{ {
_regionCreator = regionCreator; _regionCreator = regionCreator;
@ -74,6 +76,7 @@ namespace Ocelot.Configuration.Creator
_serviceProviderConfigCreator = serviceProviderConfigCreator; _serviceProviderConfigCreator = serviceProviderConfigCreator;
_qosOptionsCreator = qosOptionsCreator; _qosOptionsCreator = qosOptionsCreator;
_fileReRouteOptionsCreator = fileReRouteOptionsCreator; _fileReRouteOptionsCreator = fileReRouteOptionsCreator;
_httpHandlerOptionsCreator = httpHandlerOptionsCreator;
} }
public async Task<Response<IOcelotConfiguration>> Create() public async Task<Response<IOcelotConfiguration>> Create()
@ -143,6 +146,8 @@ namespace Ocelot.Configuration.Creator
var region = _regionCreator.Create(fileReRoute); var region = _regionCreator.Create(fileReRoute);
var httpHandlerOptions = _httpHandlerOptionsCreator.Create(fileReRoute);
var reRoute = new ReRouteBuilder() var reRoute = new ReRouteBuilder()
.WithDownstreamPathTemplate(fileReRoute.DownstreamPathTemplate) .WithDownstreamPathTemplate(fileReRoute.DownstreamPathTemplate)
.WithUpstreamPathTemplate(fileReRoute.UpstreamPathTemplate) .WithUpstreamPathTemplate(fileReRoute.UpstreamPathTemplate)
@ -168,7 +173,7 @@ namespace Ocelot.Configuration.Creator
.WithQosOptions(qosOptions) .WithQosOptions(qosOptions)
.WithEnableRateLimiting(fileReRouteOptions.EnableRateLimiting) .WithEnableRateLimiting(fileReRouteOptions.EnableRateLimiting)
.WithRateLimitOptions(rateLimitOption) .WithRateLimitOptions(rateLimitOption)
.WithAuthenticationProviderKey(fileReRoute.AuthenticationOptions.AuthenticationProviderKey) .WithHttpHandlerOptions(httpHandlerOptions)
.Build(); .Build();
await SetupLoadBalancer(reRoute); await SetupLoadBalancer(reRoute);

View File

@ -0,0 +1,13 @@
using Ocelot.Configuration.File;
namespace Ocelot.Configuration.Creator
{
public class HttpHandlerOptionsCreator : IHttpHandlerOptionsCreator
{
public HttpHandlerOptions Create(FileReRoute fileReRoute)
{
return new HttpHandlerOptions(fileReRoute.HttpHandlerOptions.AllowAutoRedirect,
fileReRoute.HttpHandlerOptions.UseCookieContainer);
}
}
}

View File

@ -0,0 +1,12 @@
using Ocelot.Configuration.File;
namespace Ocelot.Configuration.Creator
{
/// <summary>
/// Describes creation of HttpHandlerOptions
/// </summary>
public interface IHttpHandlerOptionsCreator
{
HttpHandlerOptions Create(FileReRoute fileReRoute);
}
}

View File

@ -41,8 +41,8 @@ namespace Ocelot.Configuration.Creator
} }
var route = reRoute.ReRouteIsCaseSensitive var route = reRoute.ReRouteIsCaseSensitive
? $"{upstreamTemplate}{RegExMatchEndString}" ? $"^{upstreamTemplate}{RegExMatchEndString}"
: $"{RegExIgnoreCase}{upstreamTemplate}{RegExMatchEndString}"; : $"^{RegExIgnoreCase}{upstreamTemplate}{RegExMatchEndString}";
return route; return route;
} }

View File

@ -0,0 +1,15 @@
namespace Ocelot.Configuration.File
{
public class FileHttpHandlerOptions
{
public FileHttpHandlerOptions()
{
AllowAutoRedirect = true;
UseCookieContainer = true;
}
public bool AllowAutoRedirect { get; set; }
public bool UseCookieContainer { get; set; }
}
}

View File

@ -15,6 +15,7 @@ namespace Ocelot.Configuration.File
QoSOptions = new FileQoSOptions(); QoSOptions = new FileQoSOptions();
RateLimitOptions = new FileRateLimitRule(); RateLimitOptions = new FileRateLimitRule();
AuthenticationOptions = new FileAuthenticationOptions(); AuthenticationOptions = new FileAuthenticationOptions();
HttpHandlerOptions = new FileHttpHandlerOptions();
} }
public string DownstreamPathTemplate { get; set; } public string DownstreamPathTemplate { get; set; }
@ -35,5 +36,6 @@ namespace Ocelot.Configuration.File
public string LoadBalancer {get;set;} public string LoadBalancer {get;set;}
public FileRateLimitRule RateLimitOptions { get; set; } public FileRateLimitRule RateLimitOptions { get; set; }
public FileAuthenticationOptions AuthenticationOptions { get; set; } public FileAuthenticationOptions AuthenticationOptions { get; set; }
public FileHttpHandlerOptions HttpHandlerOptions { get; set; }
} }
} }

View File

@ -0,0 +1,25 @@
namespace Ocelot.Configuration
{
/// <summary>
/// Describes configuration parameters for http handler,
/// that is created to handle a request to service
/// </summary>
public class HttpHandlerOptions
{
public HttpHandlerOptions(bool allowAutoRedirect, bool useCookieContainer)
{
AllowAutoRedirect = allowAutoRedirect;
UseCookieContainer = useCookieContainer;
}
/// <summary>
/// Specify if auto redirect is enabled
/// </summary>
public bool AllowAutoRedirect { get; private set; }
/// <summary>
/// Specify is handler has to use a cookie container
/// </summary>
public bool UseCookieContainer { get; private set; }
}
}

View File

@ -30,7 +30,7 @@ namespace Ocelot.Configuration
QoSOptions qosOptions, QoSOptions qosOptions,
bool enableEndpointRateLimiting, bool enableEndpointRateLimiting,
RateLimitOptions ratelimitOptions, RateLimitOptions ratelimitOptions,
string authenticationProviderKey) HttpHandlerOptions httpHandlerOptions)
{ {
ReRouteKey = reRouteKey; ReRouteKey = reRouteKey;
ServiceProviderConfiguraion = serviceProviderConfiguraion; ServiceProviderConfiguraion = serviceProviderConfiguraion;
@ -59,7 +59,7 @@ namespace Ocelot.Configuration
QosOptionsOptions = qosOptions; QosOptionsOptions = qosOptions;
EnableEndpointEndpointRateLimiting = enableEndpointRateLimiting; EnableEndpointEndpointRateLimiting = enableEndpointRateLimiting;
RateLimitOptions = ratelimitOptions; RateLimitOptions = ratelimitOptions;
AuthenticationProviderKey = authenticationProviderKey; HttpHandlerOptions = httpHandlerOptions;
} }
public string ReRouteKey {get;private set;} public string ReRouteKey {get;private set;}
@ -86,6 +86,6 @@ namespace Ocelot.Configuration
public ServiceProviderConfiguration ServiceProviderConfiguraion { get; private set; } public ServiceProviderConfiguration ServiceProviderConfiguraion { get; private set; }
public bool EnableEndpointEndpointRateLimiting { get; private set; } public bool EnableEndpointEndpointRateLimiting { get; private set; }
public RateLimitOptions RateLimitOptions { get; private set; } public RateLimitOptions RateLimitOptions { get; private set; }
public string AuthenticationProviderKey { get; private set; } public HttpHandlerOptions HttpHandlerOptions { get; private set; }
} }
} }

View File

@ -124,6 +124,7 @@ namespace Ocelot.DependencyInjection
services.TryAddSingleton<IRateLimitCounterHandler, MemoryCacheRateLimitCounterHandler>(); services.TryAddSingleton<IRateLimitCounterHandler, MemoryCacheRateLimitCounterHandler>();
services.TryAddSingleton<IHttpClientCache, MemoryHttpClientCache>(); services.TryAddSingleton<IHttpClientCache, MemoryHttpClientCache>();
services.TryAddSingleton<IRequestMapper, RequestMapper>(); services.TryAddSingleton<IRequestMapper, RequestMapper>();
services.TryAddSingleton<IHttpHandlerOptionsCreator, HttpHandlerOptionsCreator>();
// see this for why we register this as singleton http://stackoverflow.com/questions/37371264/invalidoperationexception-unable-to-resolve-service-for-type-microsoft-aspnetc // see this for why we register this as singleton http://stackoverflow.com/questions/37371264/invalidoperationexception-unable-to-resolve-service-for-type-microsoft-aspnetc
// could maybe use a scoped data repository // could maybe use a scoped data repository

View File

@ -10,9 +10,11 @@ namespace Ocelot.Request.Builder
public async Task<Response<Request>> Build( public async Task<Response<Request>> Build(
HttpRequestMessage httpRequestMessage, HttpRequestMessage httpRequestMessage,
bool isQos, bool isQos,
IQoSProvider qosProvider) IQoSProvider qosProvider,
bool useCookieContainer,
bool allowAutoRedirect)
{ {
return new OkResponse<Request>(new Request(httpRequestMessage, isQos, qosProvider)); return new OkResponse<Request>(new Request(httpRequestMessage, isQos, qosProvider, useCookieContainer, allowAutoRedirect));
} }
} }
} }

View File

@ -11,6 +11,8 @@
Task<Response<Request>> Build( Task<Response<Request>> Build(
HttpRequestMessage httpRequestMessage, HttpRequestMessage httpRequestMessage,
bool isQos, bool isQos,
IQoSProvider qosProvider); IQoSProvider qosProvider,
bool useCookieContainer,
bool allowAutoRedirect);
} }
} }

View File

@ -46,7 +46,9 @@ namespace Ocelot.Request.Middleware
var buildResult = await _requestCreator.Build( var buildResult = await _requestCreator.Build(
DownstreamRequest, DownstreamRequest,
DownstreamRoute.ReRoute.IsQos, DownstreamRoute.ReRoute.IsQos,
qosProvider.Data); qosProvider.Data,
DownstreamRoute.ReRoute.HttpHandlerOptions.UseCookieContainer,
DownstreamRoute.ReRoute.HttpHandlerOptions.AllowAutoRedirect);
if (buildResult.IsError) if (buildResult.IsError)
{ {

View File

@ -8,15 +8,21 @@ namespace Ocelot.Request
public Request( public Request(
HttpRequestMessage httpRequestMessage, HttpRequestMessage httpRequestMessage,
bool isQos, bool isQos,
IQoSProvider qosProvider) IQoSProvider qosProvider,
bool allowAutoRedirect,
bool useCookieContainer)
{ {
HttpRequestMessage = httpRequestMessage; HttpRequestMessage = httpRequestMessage;
IsQos = isQos; IsQos = isQos;
QosProvider = qosProvider; QosProvider = qosProvider;
AllowAutoRedirect = allowAutoRedirect;
UseCookieContainer = useCookieContainer;
} }
public HttpRequestMessage HttpRequestMessage { get; private set; } public HttpRequestMessage HttpRequestMessage { get; private set; }
public bool IsQos { get; private set; } public bool IsQos { get; private set; }
public IQoSProvider QosProvider { get; private set; } public IQoSProvider QosProvider { get; private set; }
public bool AllowAutoRedirect { get; private set; }
public bool UseCookieContainer { get; private set; }
} }
} }

View File

@ -20,9 +20,9 @@ namespace Ocelot.Requester
return this; return this;
} }
public IHttpClient Create() public IHttpClient Create(bool useCookies, bool allowAutoRedirect)
{ {
var httpclientHandler = new HttpClientHandler(); var httpclientHandler = new HttpClientHandler { AllowAutoRedirect = allowAutoRedirect, UseCookies = useCookies};
var client = new HttpClient(CreateHttpMessageHandler(httpclientHandler)); var client = new HttpClient(CreateHttpMessageHandler(httpclientHandler));

View File

@ -2,6 +2,7 @@
using System.Collections.Concurrent; using System.Collections.Concurrent;
using System.Net.Http; using System.Net.Http;
using System.Threading.Tasks; using System.Threading.Tasks;
using Ocelot.Configuration;
using Ocelot.Logging; using Ocelot.Logging;
using Ocelot.Responses; using Ocelot.Responses;
using Polly.CircuitBreaker; using Polly.CircuitBreaker;
@ -14,7 +15,8 @@ namespace Ocelot.Requester
private readonly IHttpClientCache _cacheHandlers; private readonly IHttpClientCache _cacheHandlers;
private readonly IOcelotLogger _logger; private readonly IOcelotLogger _logger;
public HttpClientHttpRequester(IOcelotLoggerFactory loggerFactory, IHttpClientCache cacheHandlers) public HttpClientHttpRequester(IOcelotLoggerFactory loggerFactory,
IHttpClientCache cacheHandlers)
{ {
_logger = loggerFactory.CreateLogger<HttpClientHttpRequester>(); _logger = loggerFactory.CreateLogger<HttpClientHttpRequester>();
_cacheHandlers = cacheHandlers; _cacheHandlers = cacheHandlers;
@ -26,7 +28,7 @@ namespace Ocelot.Requester
var cacheKey = GetCacheKey(request, builder); var cacheKey = GetCacheKey(request, builder);
var httpClient = GetHttpClient(cacheKey, builder); var httpClient = GetHttpClient(cacheKey, builder, request.UseCookieContainer, request.AllowAutoRedirect);
try try
{ {
@ -54,13 +56,13 @@ namespace Ocelot.Requester
} }
private IHttpClient GetHttpClient(string cacheKey, IHttpClientBuilder builder) private IHttpClient GetHttpClient(string cacheKey, IHttpClientBuilder builder, bool useCookieContainer, bool allowAutoRedirect)
{ {
var httpClient = _cacheHandlers.Get(cacheKey); var httpClient = _cacheHandlers.Get(cacheKey);
if (httpClient == null) if (httpClient == null)
{ {
httpClient = builder.Create(); httpClient = builder.Create(useCookieContainer, allowAutoRedirect);
} }
return httpClient; return httpClient;
} }

View File

@ -20,6 +20,8 @@ namespace Ocelot.Requester
/// <summary> /// <summary>
/// Creates the <see cref="HttpClient"/> /// Creates the <see cref="HttpClient"/>
/// </summary> /// </summary>
IHttpClient Create(); /// <param name="useCookies">Defines if http client should use cookie container</param>
/// <param name="allowAutoRedirect">Defines if http client should allow auto redirect</param>
IHttpClient Create(bool useCookies, bool allowAutoRedirect);
} }
} }

View File

@ -98,7 +98,7 @@ namespace Ocelot.AcceptanceTests
DownstreamScheme = "http", DownstreamScheme = "http",
DownstreamHost = "localhost", DownstreamHost = "localhost",
DownstreamPort = 51880, DownstreamPort = 51880,
UpstreamPathTemplate = "working", UpstreamPathTemplate = "/working",
UpstreamHttpMethod = new List<string> { "Get" }, UpstreamHttpMethod = new List<string> { "Get" },
} }
} }

View File

@ -61,6 +61,47 @@ namespace Ocelot.AcceptanceTests
.BDDfy(); .BDDfy();
} }
[Fact]
public void bug()
{
var configuration = new FileConfiguration
{
ReRoutes = new List<FileReRoute>
{
new FileReRoute
{
DownstreamPathTemplate = "/api/v1/vacancy",
DownstreamScheme = "http",
DownstreamHost = "localhost",
DownstreamPort = 51879,
UpstreamPathTemplate = "/vacancy/",
UpstreamHttpMethod = new List<string> { "Options", "Put", "Get", "Post", "Delete" },
ServiceName = "botCore",
LoadBalancer = "LeastConnection"
},
new FileReRoute
{
DownstreamPathTemplate = "/api/v1/vacancy/{vacancyId}",
DownstreamScheme = "http",
DownstreamHost = "localhost",
DownstreamPort = 51879,
UpstreamPathTemplate = "/vacancy/{vacancyId}",
UpstreamHttpMethod = new List<string> { "Options", "Put", "Get", "Post", "Delete" },
ServiceName = "botCore",
LoadBalancer = "LeastConnection"
}
}
};
this.Given(x => x.GivenThereIsAServiceRunningOn("http://localhost:51879", "/api/v1/vacancy/1", 200, "Hello from Laura"))
.And(x => _steps.GivenThereIsAConfiguration(configuration))
.And(x => _steps.GivenOcelotIsRunning())
.When(x => _steps.WhenIGetUrlOnTheApiGateway("/vacancy/1"))
.Then(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.OK))
.And(x => _steps.ThenTheResponseBodyShouldBe("Hello from Laura"))
.BDDfy();
}
[Fact] [Fact]
public void should_return_response_200_when_path_missing_forward_slash_as_first_char() public void should_return_response_200_when_path_missing_forward_slash_as_first_char()
{ {
@ -402,6 +443,46 @@ namespace Ocelot.AcceptanceTests
.BDDfy(); .BDDfy();
} }
[Fact]
public void should_return_404_when_calling_upstream_route_with_no_matching_downstream_re_route_github_issue_134()
{
var configuration = new FileConfiguration
{
ReRoutes = new List<FileReRoute>
{
new FileReRoute
{
DownstreamPathTemplate = "/api/v1/vacancy",
DownstreamScheme = "http",
DownstreamHost = "localhost",
DownstreamPort = 51879,
UpstreamPathTemplate = "/vacancy/",
UpstreamHttpMethod = new List<string> { "Options", "Put", "Get", "Post", "Delete" },
ServiceName = "botCore",
LoadBalancer = "LeastConnection"
},
new FileReRoute
{
DownstreamPathTemplate = "/api/v1/vacancy/{vacancyId}",
DownstreamScheme = "http",
DownstreamHost = "localhost",
DownstreamPort = 51879,
UpstreamPathTemplate = "/vacancy/{vacancyId}",
UpstreamHttpMethod = new List<string> { "Options", "Put", "Get", "Post", "Delete" },
ServiceName = "botCore",
LoadBalancer = "LeastConnection"
}
}
};
this.Given(x => x.GivenThereIsAServiceRunningOn("http://localhost:51879", "/api/v1/vacancy/1", 200, "Hello from Laura"))
.And(x => _steps.GivenThereIsAConfiguration(configuration))
.And(x => _steps.GivenOcelotIsRunning())
.When(x => _steps.WhenIGetUrlOnTheApiGateway("api/vacancy/1"))
.Then(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.NotFound))
.BDDfy();
}
private void GivenThereIsAServiceRunningOn(string baseUrl, string basePath, int statusCode, string responseBody) private void GivenThereIsAServiceRunningOn(string baseUrl, string basePath, int statusCode, string responseBody)
{ {
_builder = new WebHostBuilder() _builder = new WebHostBuilder()

View File

@ -14,8 +14,8 @@ namespace Ocelot.ManualTest
}); });
builder.UseKestrel() builder.UseKestrel()
.UseContentRoot(Directory.GetCurrentDirectory()) .UseContentRoot(Directory.GetCurrentDirectory())
.UseIISIntegration()
.UseStartup<Startup>(); .UseStartup<Startup>();
var host = builder.Build(); var host = builder.Build();
host.Run(); host.Run();
} }

View File

@ -45,6 +45,7 @@ namespace Ocelot.UnitTests.Configuration
private Mock<IReRouteOptionsCreator> _fileReRouteOptionsCreator; private Mock<IReRouteOptionsCreator> _fileReRouteOptionsCreator;
private Mock<IRateLimitOptionsCreator> _rateLimitOptions; private Mock<IRateLimitOptionsCreator> _rateLimitOptions;
private Mock<IRegionCreator> _regionCreator; private Mock<IRegionCreator> _regionCreator;
private Mock<IHttpHandlerOptionsCreator> _httpHandlerOptionsCreator;
public FileConfigurationCreatorTests() public FileConfigurationCreatorTests()
{ {
@ -66,6 +67,7 @@ namespace Ocelot.UnitTests.Configuration
_fileReRouteOptionsCreator = new Mock<IReRouteOptionsCreator>(); _fileReRouteOptionsCreator = new Mock<IReRouteOptionsCreator>();
_rateLimitOptions = new Mock<IRateLimitOptionsCreator>(); _rateLimitOptions = new Mock<IRateLimitOptionsCreator>();
_regionCreator = new Mock<IRegionCreator>(); _regionCreator = new Mock<IRegionCreator>();
_httpHandlerOptionsCreator = new Mock<IHttpHandlerOptionsCreator>();
_ocelotConfigurationCreator = new FileOcelotConfigurationCreator( _ocelotConfigurationCreator = new FileOcelotConfigurationCreator(
_fileConfig.Object, _validator.Object, _logger.Object, _fileConfig.Object, _validator.Object, _logger.Object,
@ -73,7 +75,7 @@ namespace Ocelot.UnitTests.Configuration
_qosProviderFactory.Object, _qosProviderHouse.Object, _claimsToThingCreator.Object, _qosProviderFactory.Object, _qosProviderHouse.Object, _claimsToThingCreator.Object,
_authOptionsCreator.Object, _upstreamTemplatePatternCreator.Object, _requestIdKeyCreator.Object, _authOptionsCreator.Object, _upstreamTemplatePatternCreator.Object, _requestIdKeyCreator.Object,
_serviceProviderConfigCreator.Object, _qosOptionsCreator.Object, _fileReRouteOptionsCreator.Object, _serviceProviderConfigCreator.Object, _qosOptionsCreator.Object, _fileReRouteOptionsCreator.Object,
_rateLimitOptions.Object, _regionCreator.Object); _rateLimitOptions.Object, _regionCreator.Object, _httpHandlerOptionsCreator.Object);
} }
[Fact] [Fact]
@ -444,6 +446,45 @@ namespace Ocelot.UnitTests.Configuration
.BDDfy(); .BDDfy();
} }
[Fact]
public void should_call_httpHandler_creator()
{
var reRouteOptions = new ReRouteOptionsBuilder()
.Build();
var httpHandlerOptions = new HttpHandlerOptions(true, true);
this.Given(x => x.GivenTheConfigIs(new FileConfiguration
{
ReRoutes = new List<FileReRoute>
{
new FileReRoute
{
DownstreamHost = "127.0.0.1",
UpstreamPathTemplate = "/api/products/{productId}",
DownstreamPathTemplate = "/products/{productId}",
UpstreamHttpMethod = new List<string> { "Get" }
}
},
}))
.And(x => x.GivenTheFollowingOptionsAreReturned(reRouteOptions))
.And(x => x.GivenTheConfigIsValid())
.And(x => x.GivenTheFollowingHttpHandlerOptionsAreReturned(httpHandlerOptions))
.When(x => x.WhenICreateTheConfig())
.Then(x => x.ThenTheHttpHandlerOptionsCreatorIsCalledCorrectly())
.BDDfy();
}
private void GivenTheFollowingHttpHandlerOptionsAreReturned(HttpHandlerOptions httpHandlerOptions)
{
_httpHandlerOptionsCreator.Setup(x => x.Create(It.IsAny<FileReRoute>()))
.Returns(httpHandlerOptions);
}
private void ThenTheHttpHandlerOptionsCreatorIsCalledCorrectly()
{
_httpHandlerOptionsCreator.Verify(x => x.Create(_fileConfiguration.ReRoutes[0]), Times.Once());
}
[Theory] [Theory]
[MemberData(nameof(AuthenticationConfigTestData.GetAuthenticationData), MemberType = typeof(AuthenticationConfigTestData))] [MemberData(nameof(AuthenticationConfigTestData.GetAuthenticationData), MemberType = typeof(AuthenticationConfigTestData))]
public void should_create_with_headers_to_extract(FileConfiguration fileConfig) public void should_create_with_headers_to_extract(FileConfiguration fileConfig)

View File

@ -0,0 +1,71 @@
using Ocelot.Configuration;
using Ocelot.Configuration.Creator;
using Ocelot.Configuration.File;
using Shouldly;
using TestStack.BDDfy;
using Xunit;
namespace Ocelot.UnitTests.Configuration
{
public class HttpHandlerOptionsCreatorTests
{
private readonly IHttpHandlerOptionsCreator _httpHandlerOptionsCreator;
private FileReRoute _fileReRoute;
private HttpHandlerOptions _httpHandlerOptions;
public HttpHandlerOptionsCreatorTests()
{
_httpHandlerOptionsCreator = new HttpHandlerOptionsCreator();
}
[Fact]
public void should_create_options_with_useCookie_and_allowAutoRedirect_true_as_default()
{
var fileReRoute = new FileReRoute();
var expectedOptions = new HttpHandlerOptions(true, true);
this.Given(x => GivenTheFollowing(fileReRoute))
.When(x => WhenICreateHttpHandlerOptions())
.Then(x => ThenTheFollowingOptionsReturned(expectedOptions))
.BDDfy();
}
[Fact]
public void should_create_options_with_specified_useCookie_and_allowAutoRedirect()
{
var fileReRoute = new FileReRoute
{
HttpHandlerOptions = new FileHttpHandlerOptions
{
AllowAutoRedirect = false,
UseCookieContainer = false
}
};
var expectedOptions = new HttpHandlerOptions(false, false);
this.Given(x => GivenTheFollowing(fileReRoute))
.When(x => WhenICreateHttpHandlerOptions())
.Then(x => ThenTheFollowingOptionsReturned(expectedOptions))
.BDDfy();
}
private void GivenTheFollowing(FileReRoute fileReRoute)
{
_fileReRoute = fileReRoute;
}
private void WhenICreateHttpHandlerOptions()
{
_httpHandlerOptions = _httpHandlerOptionsCreator.Create(_fileReRoute);
}
private void ThenTheFollowingOptionsReturned(HttpHandlerOptions options)
{
_httpHandlerOptions.ShouldNotBeNull();
_httpHandlerOptions.AllowAutoRedirect.ShouldBe(options.AllowAutoRedirect);
_httpHandlerOptions.UseCookieContainer.ShouldBe(options.UseCookieContainer);
}
}
}

View File

@ -28,7 +28,7 @@ namespace Ocelot.UnitTests.Configuration
this.Given(x => x.GivenTheFollowingFileReRoute(fileReRoute)) this.Given(x => x.GivenTheFollowingFileReRoute(fileReRoute))
.When(x => x.WhenICreateTheTemplatePattern()) .When(x => x.WhenICreateTheTemplatePattern())
.Then(x => x.ThenTheFollowingIsReturned("(?i)/PRODUCTS/.*/$")) .Then(x => x.ThenTheFollowingIsReturned("^(?i)/PRODUCTS/.*/$"))
.BDDfy(); .BDDfy();
} }
@ -42,7 +42,7 @@ namespace Ocelot.UnitTests.Configuration
}; };
this.Given(x => x.GivenTheFollowingFileReRoute(fileReRoute)) this.Given(x => x.GivenTheFollowingFileReRoute(fileReRoute))
.When(x => x.WhenICreateTheTemplatePattern()) .When(x => x.WhenICreateTheTemplatePattern())
.Then(x => x.ThenTheFollowingIsReturned("/PRODUCTS/.*/$")) .Then(x => x.ThenTheFollowingIsReturned("^/PRODUCTS/.*/$"))
.BDDfy(); .BDDfy();
} }
@ -57,7 +57,7 @@ namespace Ocelot.UnitTests.Configuration
this.Given(x => x.GivenTheFollowingFileReRoute(fileReRoute)) this.Given(x => x.GivenTheFollowingFileReRoute(fileReRoute))
.When(x => x.WhenICreateTheTemplatePattern()) .When(x => x.WhenICreateTheTemplatePattern())
.Then(x => x.ThenTheFollowingIsReturned("/api/products/.*/$")) .Then(x => x.ThenTheFollowingIsReturned("^/api/products/.*/$"))
.BDDfy(); .BDDfy();
} }
@ -72,7 +72,7 @@ namespace Ocelot.UnitTests.Configuration
this.Given(x => x.GivenTheFollowingFileReRoute(fileReRoute)) this.Given(x => x.GivenTheFollowingFileReRoute(fileReRoute))
.When(x => x.WhenICreateTheTemplatePattern()) .When(x => x.WhenICreateTheTemplatePattern())
.Then(x => x.ThenTheFollowingIsReturned("/api/products/.*/variants/.*/$")) .Then(x => x.ThenTheFollowingIsReturned("^/api/products/.*/variants/.*/$"))
.BDDfy(); .BDDfy();
} }
[Fact] [Fact]
@ -86,7 +86,7 @@ namespace Ocelot.UnitTests.Configuration
this.Given(x => x.GivenTheFollowingFileReRoute(fileReRoute)) this.Given(x => x.GivenTheFollowingFileReRoute(fileReRoute))
.When(x => x.WhenICreateTheTemplatePattern()) .When(x => x.WhenICreateTheTemplatePattern())
.Then(x => x.ThenTheFollowingIsReturned("/api/products/.*/variants/.*/$")) .Then(x => x.ThenTheFollowingIsReturned("^/api/products/.*/variants/.*/$"))
.BDDfy(); .BDDfy();
} }

View File

@ -28,6 +28,16 @@ namespace Ocelot.UnitTests.DownstreamRouteFinder.UrlMatcher
.BDDfy(); .BDDfy();
} }
[Fact]
public void should_not_match_issue_134()
{
this.Given(x => x.GivenIHaveAUpstreamPath("/api/vacancy/1/"))
.And(x => x.GivenIHaveAnUpstreamUrlTemplatePattern("^(?i)/vacancy/.*/$"))
.When(x => x.WhenIMatchThePaths())
.And(x => x.ThenTheResultIsFalse())
.BDDfy();
}
[Fact] [Fact]
public void should_match_forward_slash_only_regex() public void should_match_forward_slash_only_regex()
{ {
@ -42,7 +52,7 @@ namespace Ocelot.UnitTests.DownstreamRouteFinder.UrlMatcher
public void should_find_match_when_template_smaller_than_valid_path() public void should_find_match_when_template_smaller_than_valid_path()
{ {
this.Given(x => x.GivenIHaveAUpstreamPath("/api/products/2354325435624623464235")) this.Given(x => x.GivenIHaveAUpstreamPath("/api/products/2354325435624623464235"))
.And(x => x.GivenIHaveAnUpstreamUrlTemplatePattern("/api/products/.*$")) .And(x => x.GivenIHaveAnUpstreamUrlTemplatePattern("^/api/products/.*$"))
.When(x => x.WhenIMatchThePaths()) .When(x => x.WhenIMatchThePaths())
.And(x => x.ThenTheResultIsTrue()) .And(x => x.ThenTheResultIsTrue())
.BDDfy(); .BDDfy();
@ -52,7 +62,7 @@ namespace Ocelot.UnitTests.DownstreamRouteFinder.UrlMatcher
public void should_not_find_match() public void should_not_find_match()
{ {
this.Given(x => x.GivenIHaveAUpstreamPath("/api/values")) this.Given(x => x.GivenIHaveAUpstreamPath("/api/values"))
.And(x => x.GivenIHaveAnUpstreamUrlTemplatePattern("/$")) .And(x => x.GivenIHaveAnUpstreamUrlTemplatePattern("^/$"))
.When(x => x.WhenIMatchThePaths()) .When(x => x.WhenIMatchThePaths())
.And(x => x.ThenTheResultIsFalse()) .And(x => x.ThenTheResultIsFalse())
.BDDfy(); .BDDfy();
@ -62,7 +72,7 @@ namespace Ocelot.UnitTests.DownstreamRouteFinder.UrlMatcher
public void can_match_down_stream_url() public void can_match_down_stream_url()
{ {
this.Given(x => x.GivenIHaveAUpstreamPath("")) this.Given(x => x.GivenIHaveAUpstreamPath(""))
.And(x => x.GivenIHaveAnUpstreamUrlTemplatePattern("$")) .And(x => x.GivenIHaveAnUpstreamUrlTemplatePattern("^$"))
.When(x => x.WhenIMatchThePaths()) .When(x => x.WhenIMatchThePaths())
.And(x => x.ThenTheResultIsTrue()) .And(x => x.ThenTheResultIsTrue())
.BDDfy(); .BDDfy();
@ -72,7 +82,7 @@ namespace Ocelot.UnitTests.DownstreamRouteFinder.UrlMatcher
public void can_match_down_stream_url_with_no_slash() public void can_match_down_stream_url_with_no_slash()
{ {
this.Given(x => x.GivenIHaveAUpstreamPath("api")) this.Given(x => x.GivenIHaveAUpstreamPath("api"))
.Given(x => x.GivenIHaveAnUpstreamUrlTemplatePattern("api$")) .Given(x => x.GivenIHaveAnUpstreamUrlTemplatePattern("^api$"))
.When(x => x.WhenIMatchThePaths()) .When(x => x.WhenIMatchThePaths())
.Then(x => x.ThenTheResultIsTrue()) .Then(x => x.ThenTheResultIsTrue())
.BDDfy(); .BDDfy();
@ -82,7 +92,7 @@ namespace Ocelot.UnitTests.DownstreamRouteFinder.UrlMatcher
public void can_match_down_stream_url_with_one_slash() public void can_match_down_stream_url_with_one_slash()
{ {
this.Given(x => x.GivenIHaveAUpstreamPath("api/")) this.Given(x => x.GivenIHaveAUpstreamPath("api/"))
.Given(x => x.GivenIHaveAnUpstreamUrlTemplatePattern("api/$")) .Given(x => x.GivenIHaveAnUpstreamUrlTemplatePattern("^api/$"))
.When(x => x.WhenIMatchThePaths()) .When(x => x.WhenIMatchThePaths())
.Then(x => x.ThenTheResultIsTrue()) .Then(x => x.ThenTheResultIsTrue())
.BDDfy(); .BDDfy();
@ -92,7 +102,7 @@ namespace Ocelot.UnitTests.DownstreamRouteFinder.UrlMatcher
public void can_match_down_stream_url_with_downstream_template() public void can_match_down_stream_url_with_downstream_template()
{ {
this.Given(x => x.GivenIHaveAUpstreamPath("api/product/products/")) this.Given(x => x.GivenIHaveAUpstreamPath("api/product/products/"))
.Given(x => x.GivenIHaveAnUpstreamUrlTemplatePattern("api/product/products/$")) .Given(x => x.GivenIHaveAnUpstreamUrlTemplatePattern("^api/product/products/$"))
.When(x => x.WhenIMatchThePaths()) .When(x => x.WhenIMatchThePaths())
.Then(x => x.ThenTheResultIsTrue()) .Then(x => x.ThenTheResultIsTrue())
.BDDfy(); .BDDfy();
@ -102,7 +112,7 @@ namespace Ocelot.UnitTests.DownstreamRouteFinder.UrlMatcher
public void can_match_down_stream_url_with_downstream_template_with_one_place_holder() public void can_match_down_stream_url_with_downstream_template_with_one_place_holder()
{ {
this.Given(x => x.GivenIHaveAUpstreamPath("api/product/products/1")) this.Given(x => x.GivenIHaveAUpstreamPath("api/product/products/1"))
.Given(x => x.GivenIHaveAnUpstreamUrlTemplatePattern("api/product/products/.*$")) .Given(x => x.GivenIHaveAnUpstreamUrlTemplatePattern("^api/product/products/.*$"))
.When(x => x.WhenIMatchThePaths()) .When(x => x.WhenIMatchThePaths())
.Then(x => x.ThenTheResultIsTrue()) .Then(x => x.ThenTheResultIsTrue())
.BDDfy(); .BDDfy();
@ -112,7 +122,7 @@ namespace Ocelot.UnitTests.DownstreamRouteFinder.UrlMatcher
public void can_match_down_stream_url_with_downstream_template_with_two_place_holders() public void can_match_down_stream_url_with_downstream_template_with_two_place_holders()
{ {
this.Given(x => x.GivenIHaveAUpstreamPath("api/product/products/1/2")) this.Given(x => x.GivenIHaveAUpstreamPath("api/product/products/1/2"))
.Given(x => x.GivenIHaveAnUpstreamUrlTemplatePattern("api/product/products/.*/.*$")) .Given(x => x.GivenIHaveAnUpstreamUrlTemplatePattern("^api/product/products/.*/.*$"))
.When(x => x.WhenIMatchThePaths()) .When(x => x.WhenIMatchThePaths())
.Then(x => x.ThenTheResultIsTrue()) .Then(x => x.ThenTheResultIsTrue())
.BDDfy(); .BDDfy();
@ -122,7 +132,7 @@ namespace Ocelot.UnitTests.DownstreamRouteFinder.UrlMatcher
public void can_match_down_stream_url_with_downstream_template_with_two_place_holders_seperated_by_something() public void can_match_down_stream_url_with_downstream_template_with_two_place_holders_seperated_by_something()
{ {
this.Given(x => x.GivenIHaveAUpstreamPath("api/product/products/1/categories/2")) this.Given(x => x.GivenIHaveAUpstreamPath("api/product/products/1/categories/2"))
.And(x => x.GivenIHaveAnUpstreamUrlTemplatePattern("api/product/products/.*/categories/.*$")) .And(x => x.GivenIHaveAnUpstreamUrlTemplatePattern("^api/product/products/.*/categories/.*$"))
.When(x => x.WhenIMatchThePaths()) .When(x => x.WhenIMatchThePaths())
.Then(x => x.ThenTheResultIsTrue()) .Then(x => x.ThenTheResultIsTrue())
.BDDfy(); .BDDfy();
@ -132,7 +142,7 @@ namespace Ocelot.UnitTests.DownstreamRouteFinder.UrlMatcher
public void can_match_down_stream_url_with_downstream_template_with_three_place_holders_seperated_by_something() public void can_match_down_stream_url_with_downstream_template_with_three_place_holders_seperated_by_something()
{ {
this.Given(x => x.GivenIHaveAUpstreamPath("api/product/products/1/categories/2/variant/123")) this.Given(x => x.GivenIHaveAUpstreamPath("api/product/products/1/categories/2/variant/123"))
.And(x => x.GivenIHaveAnUpstreamUrlTemplatePattern("api/product/products/.*/categories/.*/variant/.*$")) .And(x => x.GivenIHaveAnUpstreamUrlTemplatePattern("^api/product/products/.*/categories/.*/variant/.*$"))
.When(x => x.WhenIMatchThePaths()) .When(x => x.WhenIMatchThePaths())
.Then(x => x.ThenTheResultIsTrue()) .Then(x => x.ThenTheResultIsTrue())
.BDDfy(); .BDDfy();
@ -142,7 +152,7 @@ namespace Ocelot.UnitTests.DownstreamRouteFinder.UrlMatcher
public void can_match_down_stream_url_with_downstream_template_with_three_place_holders() public void can_match_down_stream_url_with_downstream_template_with_three_place_holders()
{ {
this.Given(x => x.GivenIHaveAUpstreamPath("api/product/products/1/categories/2/variant/")) this.Given(x => x.GivenIHaveAUpstreamPath("api/product/products/1/categories/2/variant/"))
.And(x => x.GivenIHaveAnUpstreamUrlTemplatePattern("api/product/products/.*/categories/.*/variant/$")) .And(x => x.GivenIHaveAnUpstreamUrlTemplatePattern("^api/product/products/.*/categories/.*/variant/$"))
.When(x => x.WhenIMatchThePaths()) .When(x => x.WhenIMatchThePaths())
.Then(x => x.ThenTheResultIsTrue()) .Then(x => x.ThenTheResultIsTrue())
.BDDfy(); .BDDfy();
@ -152,7 +162,7 @@ namespace Ocelot.UnitTests.DownstreamRouteFinder.UrlMatcher
public void should_ignore_case_sensitivity() public void should_ignore_case_sensitivity()
{ {
this.Given(x => x.GivenIHaveAUpstreamPath("API/product/products/1/categories/2/variant/")) this.Given(x => x.GivenIHaveAUpstreamPath("API/product/products/1/categories/2/variant/"))
.And(x => x.GivenIHaveAnUpstreamUrlTemplatePattern("(?i)api/product/products/.*/categories/.*/variant/$")) .And(x => x.GivenIHaveAnUpstreamUrlTemplatePattern("^(?i)api/product/products/.*/categories/.*/variant/$"))
.When(x => x.WhenIMatchThePaths()) .When(x => x.WhenIMatchThePaths())
.Then(x => x.ThenTheResultIsTrue()) .Then(x => x.ThenTheResultIsTrue())
.BDDfy(); .BDDfy();
@ -162,7 +172,7 @@ namespace Ocelot.UnitTests.DownstreamRouteFinder.UrlMatcher
public void should_respect_case_sensitivity() public void should_respect_case_sensitivity()
{ {
this.Given(x => x.GivenIHaveAUpstreamPath("API/product/products/1/categories/2/variant/")) this.Given(x => x.GivenIHaveAUpstreamPath("API/product/products/1/categories/2/variant/"))
.And(x => x.GivenIHaveAnUpstreamUrlTemplatePattern("api/product/products/.*/categories/.*/variant/$")) .And(x => x.GivenIHaveAnUpstreamUrlTemplatePattern("^api/product/products/.*/categories/.*/variant/$"))
.When(x => x.WhenIMatchThePaths()) .When(x => x.WhenIMatchThePaths())
.Then(x => x.ThenTheResultIsFalse()) .Then(x => x.ThenTheResultIsFalse())
.BDDfy(); .BDDfy();

View File

@ -15,6 +15,7 @@
using TestStack.BDDfy; using TestStack.BDDfy;
using Xunit; using Xunit;
using Ocelot.Requester.QoS; using Ocelot.Requester.QoS;
using Ocelot.Configuration;
using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Builder;
public class HttpRequestBuilderMiddlewareTests : ServerHostedMiddlewareTest public class HttpRequestBuilderMiddlewareTests : ServerHostedMiddlewareTest
@ -50,12 +51,13 @@
new ReRouteBuilder() new ReRouteBuilder()
.WithRequestIdKey("LSRequestId") .WithRequestIdKey("LSRequestId")
.WithUpstreamHttpMethod(new List<string> { "Get" }) .WithUpstreamHttpMethod(new List<string> { "Get" })
.WithHttpHandlerOptions(new HttpHandlerOptions(true, true))
.Build()); .Build());
this.Given(x => x.GivenTheDownStreamUrlIs("any old string")) this.Given(x => x.GivenTheDownStreamUrlIs("any old string"))
.And(x => x.GivenTheQosProviderHouseReturns(new OkResponse<IQoSProvider>(new NoQoSProvider()))) .And(x => x.GivenTheQosProviderHouseReturns(new OkResponse<IQoSProvider>(new NoQoSProvider())))
.And(x => x.GivenTheDownStreamRouteIs(downstreamRoute)) .And(x => x.GivenTheDownStreamRouteIs(downstreamRoute))
.And(x => x.GivenTheRequestBuilderReturns(new Ocelot.Request.Request(new HttpRequestMessage(), true, new NoQoSProvider()))) .And(x => x.GivenTheRequestBuilderReturns(new Ocelot.Request.Request(new HttpRequestMessage(), true, new NoQoSProvider(), false, false)))
.When(x => x.WhenICallTheMiddleware()) .When(x => x.WhenICallTheMiddleware())
.Then(x => x.ThenTheScopedDataRepositoryIsCalledCorrectly()) .Then(x => x.ThenTheScopedDataRepositoryIsCalledCorrectly())
.BDDfy(); .BDDfy();
@ -103,7 +105,11 @@
_request = new OkResponse<Ocelot.Request.Request>(request); _request = new OkResponse<Ocelot.Request.Request>(request);
_requestBuilder _requestBuilder
.Setup(x => x.Build(It.IsAny<HttpRequestMessage>(), It.IsAny<bool>(), It.IsAny<IQoSProvider>())) .Setup(x => x.Build(It.IsAny<HttpRequestMessage>(),
It.IsAny<bool>(),
It.IsAny<IQoSProvider>(),
It.IsAny<bool>(),
It.IsAny<bool>()))
.ReturnsAsync(_request); .ReturnsAsync(_request);
} }

View File

@ -15,6 +15,9 @@
private readonly bool _isQos; private readonly bool _isQos;
private readonly IQoSProvider _qoSProvider; private readonly IQoSProvider _qoSProvider;
private readonly HttpRequestMessage _requestMessage; private readonly HttpRequestMessage _requestMessage;
private readonly bool _useCookieContainer;
private readonly bool _allowAutoRedirect;
private Response<Ocelot.Request.Request> _response; private Response<Ocelot.Request.Request> _response;
public HttpRequestCreatorTests() public HttpRequestCreatorTests()
@ -22,6 +25,9 @@
_requestCreator = new HttpRequestCreator(); _requestCreator = new HttpRequestCreator();
_isQos = true; _isQos = true;
_qoSProvider = new NoQoSProvider(); _qoSProvider = new NoQoSProvider();
_useCookieContainer = false;
_allowAutoRedirect = false;
_requestMessage = new HttpRequestMessage(); _requestMessage = new HttpRequestMessage();
} }
@ -30,12 +36,19 @@
{ {
this.When(x => x.WhenIBuildARequest()) this.When(x => x.WhenIBuildARequest())
.Then(x => x.ThenTheRequestContainsTheRequestMessage()) .Then(x => x.ThenTheRequestContainsTheRequestMessage())
.Then(x => x.ThenTheRequestContainsTheIsQos())
.Then(x => x.ThenTheRequestContainsTheQosProvider())
.Then(x => x.ThenTheRequestContainsUseCookieContainer())
.Then(x => x.ThenTheRequestContainsAllowAutoRedirect())
.BDDfy(); .BDDfy();
} }
private void WhenIBuildARequest() private void WhenIBuildARequest()
{ {
_response = _requestCreator.Build(_requestMessage, _isQos, _qoSProvider).GetAwaiter().GetResult(); _response = _requestCreator.Build(_requestMessage,
_isQos, _qoSProvider, _useCookieContainer, _allowAutoRedirect)
.GetAwaiter()
.GetResult();
} }
private void ThenTheRequestContainsTheRequestMessage() private void ThenTheRequestContainsTheRequestMessage()
@ -52,5 +65,15 @@
{ {
_response.Data.QosProvider.ShouldBe(_qoSProvider); _response.Data.QosProvider.ShouldBe(_qoSProvider);
} }
private void ThenTheRequestContainsUseCookieContainer()
{
_response.Data.UseCookieContainer.ShouldBe(_useCookieContainer);
}
private void ThenTheRequestContainsAllowAutoRedirect()
{
_response.Data.AllowAutoRedirect.ShouldBe(_allowAutoRedirect);
}
} }
} }

View File

@ -28,7 +28,7 @@
[Fact] [Fact]
public void should_call_scoped_data_repository_correctly() public void should_call_scoped_data_repository_correctly()
{ {
this.Given(x => x.GivenTheRequestIs(new Ocelot.Request.Request(new HttpRequestMessage(),true, new NoQoSProvider()))) this.Given(x => x.GivenTheRequestIs(new Ocelot.Request.Request(new HttpRequestMessage(),true, new NoQoSProvider(), false, false)))
.And(x => x.GivenTheRequesterReturns(new HttpResponseMessage())) .And(x => x.GivenTheRequesterReturns(new HttpResponseMessage()))
.And(x => x.GivenTheScopedRepoReturns()) .And(x => x.GivenTheScopedRepoReturns())
.When(x => x.WhenICallTheMiddleware()) .When(x => x.WhenICallTheMiddleware())

View File

@ -1,4 +1,4 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<packages> <packages>
<package id="Cake" version="0.17.0" /> <package id="Cake" version="0.23.0" />
</packages> </packages>