migrate subdomain redirects to Azure
This commit is contained in:
parent
5e6f1640dc
commit
9d86f20ca7
|
@ -17,6 +17,7 @@
|
||||||
|
|
||||||
* For SMAPI developers:
|
* For SMAPI developers:
|
||||||
* When deploying web services to a single-instance app, the MongoDB server can now be replaced with in-memory storage.
|
* When deploying web services to a single-instance app, the MongoDB server can now be replaced with in-memory storage.
|
||||||
|
* Merged the separate legacy redirects app on AWS into the main app on Azure.
|
||||||
|
|
||||||
## 3.5
|
## 3.5
|
||||||
Released 27 April 2020 for Stardew Valley 1.4.1 or later.
|
Released 27 April 2020 for Stardew Valley 1.4.1 or later.
|
||||||
|
|
|
@ -1,33 +0,0 @@
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
using Microsoft.AspNetCore.Mvc;
|
|
||||||
using Pathoschild.Http.Client;
|
|
||||||
using StardewModdingAPI.Toolkit.Framework.Clients.WebApi;
|
|
||||||
|
|
||||||
namespace SMAPI.Web.LegacyRedirects.Controllers
|
|
||||||
{
|
|
||||||
/// <summary>Provides an API to perform mod update checks.</summary>
|
|
||||||
[ApiController]
|
|
||||||
[Produces("application/json")]
|
|
||||||
[Route("api/v{version}/mods")]
|
|
||||||
public class ModsApiController : Controller
|
|
||||||
{
|
|
||||||
/*********
|
|
||||||
** Public methods
|
|
||||||
*********/
|
|
||||||
/// <summary>Fetch version metadata for the given mods.</summary>
|
|
||||||
/// <param name="model">The mod search criteria.</param>
|
|
||||||
[HttpPost]
|
|
||||||
public async Task<IEnumerable<ModEntryModel>> PostAsync([FromBody] ModSearchModel model)
|
|
||||||
{
|
|
||||||
using IClient client = new FluentClient("https://smapi.io/api");
|
|
||||||
|
|
||||||
Startup.ConfigureJsonNet(client.Formatters.JsonFormatter.SerializerSettings);
|
|
||||||
|
|
||||||
return await client
|
|
||||||
.PostAsync(this.Request.Path)
|
|
||||||
.WithBody(model)
|
|
||||||
.AsArray<ModEntryModel>();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,37 +0,0 @@
|
||||||
using System;
|
|
||||||
using Microsoft.AspNetCore.Http;
|
|
||||||
using Microsoft.AspNetCore.Rewrite;
|
|
||||||
|
|
||||||
namespace SMAPI.Web.LegacyRedirects.Framework
|
|
||||||
{
|
|
||||||
/// <summary>Rewrite requests to prepend the subdomain portion (if any) to the path.</summary>
|
|
||||||
/// <remarks>Derived from <a href="https://stackoverflow.com/a/44526747/262123" />.</remarks>
|
|
||||||
internal class LambdaRewriteRule : IRule
|
|
||||||
{
|
|
||||||
/*********
|
|
||||||
** Accessors
|
|
||||||
*********/
|
|
||||||
/// <summary>Rewrite an HTTP request if needed.</summary>
|
|
||||||
private readonly Action<RewriteContext, HttpRequest, HttpResponse> Rewrite;
|
|
||||||
|
|
||||||
|
|
||||||
/*********
|
|
||||||
** Public methods
|
|
||||||
*********/
|
|
||||||
/// <summary>Construct an instance.</summary>
|
|
||||||
/// <param name="rewrite">Rewrite an HTTP request if needed.</param>
|
|
||||||
public LambdaRewriteRule(Action<RewriteContext, HttpRequest, HttpResponse> rewrite)
|
|
||||||
{
|
|
||||||
this.Rewrite = rewrite ?? throw new ArgumentNullException(nameof(rewrite));
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>Applies the rule. Implementations of ApplyRule should set the value for <see cref="RewriteContext.Result" /> (defaults to RuleResult.ContinueRules).</summary>
|
|
||||||
/// <param name="context">The rewrite context.</param>
|
|
||||||
public void ApplyRule(RewriteContext context)
|
|
||||||
{
|
|
||||||
HttpRequest request = context.HttpContext.Request;
|
|
||||||
HttpResponse response = context.HttpContext.Response;
|
|
||||||
this.Rewrite(context, request, response);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,23 +0,0 @@
|
||||||
using Microsoft.AspNetCore.Hosting;
|
|
||||||
using Microsoft.Extensions.Hosting;
|
|
||||||
|
|
||||||
namespace SMAPI.Web.LegacyRedirects
|
|
||||||
{
|
|
||||||
/// <summary>The main app entry point.</summary>
|
|
||||||
public class Program
|
|
||||||
{
|
|
||||||
/*********
|
|
||||||
** Public methods
|
|
||||||
*********/
|
|
||||||
/// <summary>The main app entry point.</summary>
|
|
||||||
/// <param name="args">The command-line arguments.</param>
|
|
||||||
public static void Main(string[] args)
|
|
||||||
{
|
|
||||||
Host
|
|
||||||
.CreateDefaultBuilder(args)
|
|
||||||
.ConfigureWebHostDefaults(builder => builder.UseStartup<Startup>())
|
|
||||||
.Build()
|
|
||||||
.Run();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,29 +0,0 @@
|
||||||
{
|
|
||||||
"iisSettings": {
|
|
||||||
"windowsAuthentication": false,
|
|
||||||
"anonymousAuthentication": true,
|
|
||||||
"iisExpress": {
|
|
||||||
"applicationUrl": "http://localhost:52756",
|
|
||||||
"sslPort": 0
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"$schema": "http://json.schemastore.org/launchsettings.json",
|
|
||||||
"profiles": {
|
|
||||||
"IIS Express": {
|
|
||||||
"commandName": "IISExpress",
|
|
||||||
"launchBrowser": true,
|
|
||||||
"environmentVariables": {
|
|
||||||
"ASPNETCORE_ENVIRONMENT": "Development"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"SMAPI.Web.LegacyRedirects": {
|
|
||||||
"commandName": "Project",
|
|
||||||
"launchBrowser": true,
|
|
||||||
"launchUrl": "/",
|
|
||||||
"environmentVariables": {
|
|
||||||
"ASPNETCORE_ENVIRONMENT": "Development"
|
|
||||||
},
|
|
||||||
"applicationUrl": "https://localhost:5001;http://localhost:5000"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,21 +0,0 @@
|
||||||
<Project Sdk="Microsoft.NET.Sdk.Web">
|
|
||||||
|
|
||||||
<PropertyGroup>
|
|
||||||
<TargetFramework>netcoreapp3.0</TargetFramework>
|
|
||||||
</PropertyGroup>
|
|
||||||
|
|
||||||
<ItemGroup>
|
|
||||||
<Content Remove="aws-beanstalk-tools-defaults.json" />
|
|
||||||
</ItemGroup>
|
|
||||||
|
|
||||||
<ItemGroup>
|
|
||||||
<PackageReference Include="Microsoft.AspNetCore.Mvc.NewtonsoftJson" Version="3.0.2" />
|
|
||||||
<PackageReference Include="Pathoschild.Http.FluentClient" Version="4.0.0" />
|
|
||||||
</ItemGroup>
|
|
||||||
|
|
||||||
<ItemGroup>
|
|
||||||
<ProjectReference Include="..\SMAPI.Toolkit.CoreInterfaces\SMAPI.Toolkit.CoreInterfaces.csproj" />
|
|
||||||
<ProjectReference Include="..\SMAPI.Toolkit\SMAPI.Toolkit.csproj" />
|
|
||||||
</ItemGroup>
|
|
||||||
|
|
||||||
</Project>
|
|
|
@ -0,0 +1,54 @@
|
||||||
|
using System;
|
||||||
|
using System.Net;
|
||||||
|
using Microsoft.AspNetCore.Rewrite;
|
||||||
|
|
||||||
|
namespace StardewModdingAPI.Web.Framework.RedirectRules
|
||||||
|
{
|
||||||
|
/// <summary>Redirect hostnames to a URL if they match a condition.</summary>
|
||||||
|
internal class RedirectHostsToUrlsRule : RedirectMatchRule
|
||||||
|
{
|
||||||
|
/*********
|
||||||
|
** Fields
|
||||||
|
*********/
|
||||||
|
/// <summary>Maps a lowercase hostname to the resulting redirect URL.</summary>
|
||||||
|
private readonly Func<string, string> Map;
|
||||||
|
|
||||||
|
|
||||||
|
/*********
|
||||||
|
** Public methods
|
||||||
|
*********/
|
||||||
|
/// <summary>Construct an instance.</summary>
|
||||||
|
/// <param name="statusCode">The status code to use for redirects.</param>
|
||||||
|
/// <param name="map">Hostnames mapped to the resulting redirect URL.</param>
|
||||||
|
public RedirectHostsToUrlsRule(HttpStatusCode statusCode, Func<string, string> map)
|
||||||
|
{
|
||||||
|
this.StatusCode = statusCode;
|
||||||
|
this.Map = map ?? throw new ArgumentNullException(nameof(map));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*********
|
||||||
|
** Private methods
|
||||||
|
*********/
|
||||||
|
/// <summary>Get the new redirect URL.</summary>
|
||||||
|
/// <param name="context">The rewrite context.</param>
|
||||||
|
/// <returns>Returns the redirect URL, or <c>null</c> if the redirect doesn't apply.</returns>
|
||||||
|
protected override string GetNewUrl(RewriteContext context)
|
||||||
|
{
|
||||||
|
// get requested host
|
||||||
|
string host = context.HttpContext.Request.Host.Host;
|
||||||
|
if (host == null)
|
||||||
|
return null;
|
||||||
|
|
||||||
|
// get new host
|
||||||
|
host = this.Map(host);
|
||||||
|
if (host == null)
|
||||||
|
return null;
|
||||||
|
|
||||||
|
// rewrite URL
|
||||||
|
UriBuilder uri = this.GetUrl(context.HttpContext.Request);
|
||||||
|
uri.Host = host;
|
||||||
|
return uri.ToString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,58 @@
|
||||||
|
using System;
|
||||||
|
using System.Net;
|
||||||
|
using Microsoft.AspNetCore.Http;
|
||||||
|
using Microsoft.AspNetCore.Rewrite;
|
||||||
|
|
||||||
|
namespace StardewModdingAPI.Web.Framework.RedirectRules
|
||||||
|
{
|
||||||
|
/// <summary>Redirect matching requests to a URL.</summary>
|
||||||
|
internal abstract class RedirectMatchRule : IRule
|
||||||
|
{
|
||||||
|
/*********
|
||||||
|
** Fields
|
||||||
|
*********/
|
||||||
|
/// <summary>The status code to use for redirects.</summary>
|
||||||
|
protected HttpStatusCode StatusCode { get; set; } = HttpStatusCode.Redirect;
|
||||||
|
|
||||||
|
|
||||||
|
/*********
|
||||||
|
** Public methods
|
||||||
|
*********/
|
||||||
|
/// <summary>Applies the rule. Implementations of ApplyRule should set the value for <see cref="RewriteContext.Result" /> (defaults to RuleResult.ContinueRules).</summary>
|
||||||
|
/// <param name="context">The rewrite context.</param>
|
||||||
|
public void ApplyRule(RewriteContext context)
|
||||||
|
{
|
||||||
|
string newUrl = this.GetNewUrl(context);
|
||||||
|
if (newUrl == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
HttpResponse response = context.HttpContext.Response;
|
||||||
|
response.StatusCode = (int)HttpStatusCode.Redirect;
|
||||||
|
response.Headers["Location"] = newUrl;
|
||||||
|
context.Result = RuleResult.EndResponse;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*********
|
||||||
|
** Protected methods
|
||||||
|
*********/
|
||||||
|
/// <summary>Get the new redirect URL.</summary>
|
||||||
|
/// <param name="context">The rewrite context.</param>
|
||||||
|
/// <returns>Returns the redirect URL, or <c>null</c> if the redirect doesn't apply.</returns>
|
||||||
|
protected abstract string GetNewUrl(RewriteContext context);
|
||||||
|
|
||||||
|
/// <summary>Get the full request URL.</summary>
|
||||||
|
/// <param name="request">The request.</param>
|
||||||
|
protected UriBuilder GetUrl(HttpRequest request)
|
||||||
|
{
|
||||||
|
return new UriBuilder
|
||||||
|
{
|
||||||
|
Scheme = request.Scheme,
|
||||||
|
Host = request.Host.Host,
|
||||||
|
Port = request.Host.Port ?? -1,
|
||||||
|
Path = request.PathBase + request.Path,
|
||||||
|
Query = request.QueryString.Value
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,54 @@
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text.RegularExpressions;
|
||||||
|
using Microsoft.AspNetCore.Rewrite;
|
||||||
|
|
||||||
|
namespace StardewModdingAPI.Web.Framework.RedirectRules
|
||||||
|
{
|
||||||
|
/// <summary>Redirect paths to URLs if they match a condition.</summary>
|
||||||
|
internal class RedirectPathsToUrlsRule : RedirectMatchRule
|
||||||
|
{
|
||||||
|
/*********
|
||||||
|
** Fields
|
||||||
|
*********/
|
||||||
|
/// <summary>Regex patterns matching the current URL mapped to the resulting redirect URL.</summary>
|
||||||
|
private readonly IDictionary<Regex, string> Map;
|
||||||
|
|
||||||
|
|
||||||
|
/*********
|
||||||
|
** Public methods
|
||||||
|
*********/
|
||||||
|
/// <summary>Construct an instance.</summary>
|
||||||
|
/// <param name="map">Regex patterns matching the current URL mapped to the resulting redirect URL.</param>
|
||||||
|
public RedirectPathsToUrlsRule(IDictionary<string, string> map)
|
||||||
|
{
|
||||||
|
this.Map = map.ToDictionary(
|
||||||
|
p => new Regex(p.Key, RegexOptions.IgnoreCase | RegexOptions.Compiled),
|
||||||
|
p => p.Value
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*********
|
||||||
|
** Protected methods
|
||||||
|
*********/
|
||||||
|
/// <summary>Get the new redirect URL.</summary>
|
||||||
|
/// <param name="context">The rewrite context.</param>
|
||||||
|
/// <returns>Returns the redirect URL, or <c>null</c> if the redirect doesn't apply.</returns>
|
||||||
|
protected override string GetNewUrl(RewriteContext context)
|
||||||
|
{
|
||||||
|
string path = context.HttpContext.Request.Path.Value;
|
||||||
|
|
||||||
|
if (!string.IsNullOrWhiteSpace(path))
|
||||||
|
{
|
||||||
|
foreach ((Regex pattern, string url) in this.Map)
|
||||||
|
{
|
||||||
|
if (pattern.IsMatch(path))
|
||||||
|
return pattern.Replace(path, url);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,47 @@
|
||||||
|
using System;
|
||||||
|
using System.Net;
|
||||||
|
using Microsoft.AspNetCore.Http;
|
||||||
|
using Microsoft.AspNetCore.Rewrite;
|
||||||
|
|
||||||
|
namespace StardewModdingAPI.Web.Framework.RedirectRules
|
||||||
|
{
|
||||||
|
/// <summary>Redirect requests to HTTPS.</summary>
|
||||||
|
internal class RedirectToHttpsRule : RedirectMatchRule
|
||||||
|
{
|
||||||
|
/*********
|
||||||
|
** Fields
|
||||||
|
*********/
|
||||||
|
/// <summary>Matches requests which should be ignored.</summary>
|
||||||
|
private readonly Func<HttpRequest, bool> Except;
|
||||||
|
|
||||||
|
|
||||||
|
/*********
|
||||||
|
** Public methods
|
||||||
|
*********/
|
||||||
|
/// <summary>Construct an instance.</summary>
|
||||||
|
/// <param name="except">Matches requests which should be ignored.</param>
|
||||||
|
public RedirectToHttpsRule(Func<HttpRequest, bool> except = null)
|
||||||
|
{
|
||||||
|
this.Except = except ?? (req => false);
|
||||||
|
this.StatusCode = HttpStatusCode.RedirectKeepVerb;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*********
|
||||||
|
** Protected methods
|
||||||
|
*********/
|
||||||
|
/// <summary>Get the new redirect URL.</summary>
|
||||||
|
/// <param name="context">The rewrite context.</param>
|
||||||
|
/// <returns>Returns the redirect URL, or <c>null</c> if the redirect doesn't apply.</returns>
|
||||||
|
protected override string GetNewUrl(RewriteContext context)
|
||||||
|
{
|
||||||
|
HttpRequest request = context.HttpContext.Request;
|
||||||
|
if (request.IsHttps || this.Except(request))
|
||||||
|
return null;
|
||||||
|
|
||||||
|
UriBuilder uri = this.GetUrl(request);
|
||||||
|
uri.Scheme = "https";
|
||||||
|
return uri.ToString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,62 +0,0 @@
|
||||||
using System;
|
|
||||||
using System.Net;
|
|
||||||
using System.Text;
|
|
||||||
using Microsoft.AspNetCore.Http;
|
|
||||||
using Microsoft.AspNetCore.Rewrite;
|
|
||||||
|
|
||||||
namespace StardewModdingAPI.Web.Framework.RewriteRules
|
|
||||||
{
|
|
||||||
/// <summary>Redirect requests to HTTPS.</summary>
|
|
||||||
/// <remarks>Derived from <a href="https://stackoverflow.com/a/44526747/262123" /> and <see cref="Microsoft.AspNetCore.Rewrite.Internal.RedirectToHttpsRule"/>.</remarks>
|
|
||||||
internal class ConditionalRedirectToHttpsRule : IRule
|
|
||||||
{
|
|
||||||
/*********
|
|
||||||
** Fields
|
|
||||||
*********/
|
|
||||||
/// <summary>A predicate which indicates when the rule should be applied.</summary>
|
|
||||||
private readonly Func<HttpRequest, bool> ShouldRewrite;
|
|
||||||
|
|
||||||
|
|
||||||
/*********
|
|
||||||
** Public methods
|
|
||||||
*********/
|
|
||||||
/// <summary>Construct an instance.</summary>
|
|
||||||
/// <param name="shouldRewrite">A predicate which indicates when the rule should be applied.</param>
|
|
||||||
public ConditionalRedirectToHttpsRule(Func<HttpRequest, bool> shouldRewrite = null)
|
|
||||||
{
|
|
||||||
this.ShouldRewrite = shouldRewrite ?? (req => true);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>Applies the rule. Implementations of ApplyRule should set the value for <see cref="RewriteContext.Result" /> (defaults to RuleResult.ContinueRules).</summary>
|
|
||||||
/// <param name="context">The rewrite context.</param>
|
|
||||||
public void ApplyRule(RewriteContext context)
|
|
||||||
{
|
|
||||||
HttpRequest request = context.HttpContext.Request;
|
|
||||||
|
|
||||||
// check condition
|
|
||||||
if (this.IsSecure(request) || !this.ShouldRewrite(request))
|
|
||||||
return;
|
|
||||||
|
|
||||||
// redirect request
|
|
||||||
HttpResponse response = context.HttpContext.Response;
|
|
||||||
response.StatusCode = (int)HttpStatusCode.RedirectKeepVerb;
|
|
||||||
response.Headers["Location"] = new StringBuilder()
|
|
||||||
.Append("https://")
|
|
||||||
.Append(request.Host.Host)
|
|
||||||
.Append(request.PathBase)
|
|
||||||
.Append(request.Path)
|
|
||||||
.Append(request.QueryString)
|
|
||||||
.ToString();
|
|
||||||
context.Result = RuleResult.EndResponse;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>Get whether the request was received over HTTPS.</summary>
|
|
||||||
/// <param name="request">The request to check.</param>
|
|
||||||
public bool IsSecure(HttpRequest request)
|
|
||||||
{
|
|
||||||
return
|
|
||||||
request.IsHttps // HTTPS to server
|
|
||||||
|| string.Equals(request.Headers["x-forwarded-proto"], "HTTPS", StringComparison.OrdinalIgnoreCase); // HTTPS to AWS load balancer
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,57 +0,0 @@
|
||||||
using System;
|
|
||||||
using System.Net;
|
|
||||||
using System.Text.RegularExpressions;
|
|
||||||
using Microsoft.AspNetCore.Http;
|
|
||||||
using Microsoft.AspNetCore.Rewrite;
|
|
||||||
|
|
||||||
namespace StardewModdingAPI.Web.Framework.RewriteRules
|
|
||||||
{
|
|
||||||
/// <summary>Redirect requests to an external URL if they match a condition.</summary>
|
|
||||||
internal class RedirectToUrlRule : IRule
|
|
||||||
{
|
|
||||||
/*********
|
|
||||||
** Fields
|
|
||||||
*********/
|
|
||||||
/// <summary>Get the new URL to which to redirect (or <c>null</c> to skip).</summary>
|
|
||||||
private readonly Func<HttpRequest, string> NewUrl;
|
|
||||||
|
|
||||||
|
|
||||||
/*********
|
|
||||||
** Public methods
|
|
||||||
*********/
|
|
||||||
/// <summary>Construct an instance.</summary>
|
|
||||||
/// <param name="shouldRewrite">A predicate which indicates when the rule should be applied.</param>
|
|
||||||
/// <param name="url">The new URL to which to redirect.</param>
|
|
||||||
public RedirectToUrlRule(Func<HttpRequest, bool> shouldRewrite, string url)
|
|
||||||
{
|
|
||||||
this.NewUrl = req => shouldRewrite(req) ? url : null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>Construct an instance.</summary>
|
|
||||||
/// <param name="pathRegex">A case-insensitive regex to match against the path.</param>
|
|
||||||
/// <param name="url">The external URL.</param>
|
|
||||||
public RedirectToUrlRule(string pathRegex, string url)
|
|
||||||
{
|
|
||||||
Regex regex = new Regex(pathRegex, RegexOptions.IgnoreCase | RegexOptions.Compiled);
|
|
||||||
this.NewUrl = req => req.Path.HasValue ? regex.Replace(req.Path.Value, url) : null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>Applies the rule. Implementations of ApplyRule should set the value for <see cref="RewriteContext.Result" /> (defaults to RuleResult.ContinueRules).</summary>
|
|
||||||
/// <param name="context">The rewrite context.</param>
|
|
||||||
public void ApplyRule(RewriteContext context)
|
|
||||||
{
|
|
||||||
HttpRequest request = context.HttpContext.Request;
|
|
||||||
|
|
||||||
// check rewrite
|
|
||||||
string newUrl = this.NewUrl(request);
|
|
||||||
if (newUrl == null || newUrl == request.Path.Value)
|
|
||||||
return;
|
|
||||||
|
|
||||||
// redirect request
|
|
||||||
HttpResponse response = context.HttpContext.Response;
|
|
||||||
response.StatusCode = (int)HttpStatusCode.Redirect;
|
|
||||||
response.Headers["Location"] = newUrl;
|
|
||||||
context.Result = RuleResult.EndResponse;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,5 +1,6 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Net;
|
||||||
using Hangfire;
|
using Hangfire;
|
||||||
using Hangfire.MemoryStorage;
|
using Hangfire.MemoryStorage;
|
||||||
using Hangfire.Mongo;
|
using Hangfire.Mongo;
|
||||||
|
@ -27,7 +28,7 @@ using StardewModdingAPI.Web.Framework.Clients.Nexus;
|
||||||
using StardewModdingAPI.Web.Framework.Clients.Pastebin;
|
using StardewModdingAPI.Web.Framework.Clients.Pastebin;
|
||||||
using StardewModdingAPI.Web.Framework.Compression;
|
using StardewModdingAPI.Web.Framework.Compression;
|
||||||
using StardewModdingAPI.Web.Framework.ConfigModels;
|
using StardewModdingAPI.Web.Framework.ConfigModels;
|
||||||
using StardewModdingAPI.Web.Framework.RewriteRules;
|
using StardewModdingAPI.Web.Framework.RedirectRules;
|
||||||
using StardewModdingAPI.Web.Framework.Storage;
|
using StardewModdingAPI.Web.Framework.Storage;
|
||||||
|
|
||||||
namespace StardewModdingAPI.Web
|
namespace StardewModdingAPI.Web
|
||||||
|
@ -270,26 +271,49 @@ namespace StardewModdingAPI.Web
|
||||||
/// <summary>Get the redirect rules to apply.</summary>
|
/// <summary>Get the redirect rules to apply.</summary>
|
||||||
private RewriteOptions GetRedirectRules()
|
private RewriteOptions GetRedirectRules()
|
||||||
{
|
{
|
||||||
var redirects = new RewriteOptions();
|
var redirects = new RewriteOptions()
|
||||||
|
// shortcut paths
|
||||||
|
.Add(new RedirectPathsToUrlsRule(new Dictionary<string, string>
|
||||||
|
{
|
||||||
|
[@"^/3\.0\.?$"] = "https://stardewvalleywiki.com/Modding:Migrate_to_SMAPI_3.0",
|
||||||
|
[@"^/(?:buildmsg|package)(?:/?(.*))$"] = "https://github.com/Pathoschild/SMAPI/blob/develop/docs/technical/mod-package.md#$1", // buildmsg deprecated, remove when SDV 1.4 is released
|
||||||
|
[@"^/community\.?$"] = "https://stardewvalleywiki.com/Modding:Community",
|
||||||
|
[@"^/compat\.?$"] = "https://smapi.io/mods",
|
||||||
|
[@"^/docs\.?$"] = "https://stardewvalleywiki.com/Modding:Index",
|
||||||
|
[@"^/install\.?$"] = "https://stardewvalleywiki.com/Modding:Player_Guide/Getting_Started#Install_SMAPI",
|
||||||
|
[@"^/troubleshoot(.*)$"] = "https://stardewvalleywiki.com/Modding:Player_Guide/Troubleshooting$1",
|
||||||
|
[@"^/xnb\.?$"] = "https://stardewvalleywiki.com/Modding:Using_XNB_mods"
|
||||||
|
}))
|
||||||
|
|
||||||
|
// legacy paths
|
||||||
|
.Add(new RedirectPathsToUrlsRule(this.GetLegacyPathRedirects()))
|
||||||
|
|
||||||
|
// subdomains
|
||||||
|
.Add(new RedirectHostsToUrlsRule(HttpStatusCode.PermanentRedirect, host => host switch
|
||||||
|
{
|
||||||
|
"api.smapi.io" => "smapi.io/api",
|
||||||
|
"json.smapi.io" => "smapi.io/json",
|
||||||
|
"log.smapi.io" => "smapi.io/log",
|
||||||
|
"mods.smapi.io" => "smapi.io/mods",
|
||||||
|
_ => host.EndsWith(".smapi.io")
|
||||||
|
? "smapi.io"
|
||||||
|
: null
|
||||||
|
}))
|
||||||
|
|
||||||
// redirect to HTTPS (except API for Linux/Mac Mono compatibility)
|
// redirect to HTTPS (except API for Linux/Mac Mono compatibility)
|
||||||
redirects.Add(new ConditionalRedirectToHttpsRule(
|
.Add(
|
||||||
shouldRewrite: req =>
|
new RedirectToHttpsRule(except: req => req.Host.Host == "localhost" || req.Path.StartsWithSegments("/api"))
|
||||||
req.Host.Host != "localhost"
|
);
|
||||||
&& !req.Path.StartsWithSegments("/api")
|
|
||||||
));
|
|
||||||
|
|
||||||
// shortcut redirects
|
return redirects;
|
||||||
redirects.Add(new RedirectToUrlRule(@"^/3\.0\.?$", "https://stardewvalleywiki.com/Modding:Migrate_to_SMAPI_3.0"));
|
}
|
||||||
redirects.Add(new RedirectToUrlRule(@"^/(?:buildmsg|package)(?:/?(.*))$", "https://github.com/Pathoschild/SMAPI/blob/develop/docs/technical/mod-package.md#$1")); // buildmsg deprecated, remove when SDV 1.4 is released
|
|
||||||
redirects.Add(new RedirectToUrlRule(@"^/community\.?$", "https://stardewvalleywiki.com/Modding:Community"));
|
|
||||||
redirects.Add(new RedirectToUrlRule(@"^/compat\.?$", "https://smapi.io/mods"));
|
|
||||||
redirects.Add(new RedirectToUrlRule(@"^/docs\.?$", "https://stardewvalleywiki.com/Modding:Index"));
|
|
||||||
redirects.Add(new RedirectToUrlRule(@"^/install\.?$", "https://stardewvalleywiki.com/Modding:Player_Guide/Getting_Started#Install_SMAPI"));
|
|
||||||
redirects.Add(new RedirectToUrlRule(@"^/troubleshoot(.*)$", "https://stardewvalleywiki.com/Modding:Player_Guide/Troubleshooting$1"));
|
|
||||||
redirects.Add(new RedirectToUrlRule(@"^/xnb\.?$", "https://stardewvalleywiki.com/Modding:Using_XNB_mods"));
|
|
||||||
|
|
||||||
// redirect legacy canimod.com URLs
|
/// <summary>Get the redirects for legacy paths that have been moved elsewhere.</summary>
|
||||||
|
private IDictionary<string, string> GetLegacyPathRedirects()
|
||||||
|
{
|
||||||
|
var redirects = new Dictionary<string, string>();
|
||||||
|
|
||||||
|
// canimod.com => wiki
|
||||||
var wikiRedirects = new Dictionary<string, string[]>
|
var wikiRedirects = new Dictionary<string, string[]>
|
||||||
{
|
{
|
||||||
["Modding:Index#Migration_guides"] = new[] { "^/for-devs/updating-a-smapi-mod", "^/guides/updating-a-smapi-mod" },
|
["Modding:Index#Migration_guides"] = new[] { "^/for-devs/updating-a-smapi-mod", "^/guides/updating-a-smapi-mod" },
|
||||||
|
@ -306,7 +330,7 @@ namespace StardewModdingAPI.Web
|
||||||
foreach ((string page, string[] patterns) in wikiRedirects)
|
foreach ((string page, string[] patterns) in wikiRedirects)
|
||||||
{
|
{
|
||||||
foreach (string pattern in patterns)
|
foreach (string pattern in patterns)
|
||||||
redirects.Add(new RedirectToUrlRule(pattern, "https://stardewvalleywiki.com/" + page));
|
redirects.Add(pattern, "https://stardewvalleywiki.com/" + page);
|
||||||
}
|
}
|
||||||
|
|
||||||
return redirects;
|
return redirects;
|
||||||
|
|
|
@ -77,8 +77,6 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SMAPI.Toolkit.CoreInterface
|
||||||
EndProject
|
EndProject
|
||||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SMAPI.Web", "SMAPI.Web\SMAPI.Web.csproj", "{80EFD92F-728F-41E0-8A5B-9F6F49A91899}"
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SMAPI.Web", "SMAPI.Web\SMAPI.Web.csproj", "{80EFD92F-728F-41E0-8A5B-9F6F49A91899}"
|
||||||
EndProject
|
EndProject
|
||||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SMAPI.Web.LegacyRedirects", "SMAPI.Web.LegacyRedirects\SMAPI.Web.LegacyRedirects.csproj", "{159AA5A5-35C2-488C-B23F-1613C80594AE}"
|
|
||||||
EndProject
|
|
||||||
Global
|
Global
|
||||||
GlobalSection(SharedMSBuildProjectFiles) = preSolution
|
GlobalSection(SharedMSBuildProjectFiles) = preSolution
|
||||||
SMAPI.Internal\SMAPI.Internal.projitems*{0634ea4c-3b8f-42db-aea6-ca9e4ef6e92f}*SharedItemsImports = 5
|
SMAPI.Internal\SMAPI.Internal.projitems*{0634ea4c-3b8f-42db-aea6-ca9e4ef6e92f}*SharedItemsImports = 5
|
||||||
|
@ -138,10 +136,6 @@ Global
|
||||||
{80EFD92F-728F-41E0-8A5B-9F6F49A91899}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
{80EFD92F-728F-41E0-8A5B-9F6F49A91899}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
{80EFD92F-728F-41E0-8A5B-9F6F49A91899}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
{80EFD92F-728F-41E0-8A5B-9F6F49A91899}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
{80EFD92F-728F-41E0-8A5B-9F6F49A91899}.Release|Any CPU.Build.0 = Release|Any CPU
|
{80EFD92F-728F-41E0-8A5B-9F6F49A91899}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
{159AA5A5-35C2-488C-B23F-1613C80594AE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
|
||||||
{159AA5A5-35C2-488C-B23F-1613C80594AE}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
|
||||||
{159AA5A5-35C2-488C-B23F-1613C80594AE}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
|
||||||
{159AA5A5-35C2-488C-B23F-1613C80594AE}.Release|Any CPU.Build.0 = Release|Any CPU
|
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
GlobalSection(SolutionProperties) = preSolution
|
GlobalSection(SolutionProperties) = preSolution
|
||||||
HideSolutionNode = FALSE
|
HideSolutionNode = FALSE
|
||||||
|
|
Loading…
Reference in New Issue