* Add support for multi segment base urls

* Make baseurl case-insensitive
This commit is contained in:
Bond_009
2019-11-17 23:05:39 +01:00
committed by Bond-009
parent e7098f1997
commit 3221e837f9
73 changed files with 1285 additions and 742 deletions

View File

@@ -1,5 +1,7 @@
using System;
using System.IO;
using System.Linq;
using MediaBrowser.Controller.Configuration;
using MediaBrowser.Controller.Dto;
using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Entities.Audio;
@@ -16,19 +18,35 @@ namespace MediaBrowser.Api
/// <summary>
/// Class BaseApiService
/// </summary>
public class BaseApiService : IService, IRequiresRequest
public abstract class BaseApiService : IService, IRequiresRequest
{
/// <summary>
/// Gets or sets the logger.
/// </summary>
/// <value>The logger.</value>
public ILogger Logger => ApiEntryPoint.Instance.Logger;
public BaseApiService(
ILogger logger,
IServerConfigurationManager serverConfigurationManager,
IHttpResultFactory httpResultFactory)
{
Logger = logger;
ServerConfigurationManager = serverConfigurationManager;
ResultFactory = httpResultFactory;
}
/// <summary>
/// Gets or sets the HTTP result factory.
/// Gets the logger.
/// </summary>
/// <value>The logger.</value>
protected ILogger Logger { get; }
/// <summary>
/// Gets or sets the server configuration manager.
/// </summary>
/// <value>The server configuration manager.</value>
protected IServerConfigurationManager ServerConfigurationManager { get; }
/// <summary>
/// Gets the HTTP result factory.
/// </summary>
/// <value>The HTTP result factory.</value>
public IHttpResultFactory ResultFactory => ApiEntryPoint.Instance.ResultFactory;
protected IHttpResultFactory ResultFactory { get; }
/// <summary>
/// Gets or sets the request context.
@@ -36,10 +54,7 @@ namespace MediaBrowser.Api
/// <value>The request context.</value>
public IRequest Request { get; set; }
public string GetHeader(string name)
{
return Request.Headers[name];
}
public string GetHeader(string name) => Request.Headers[name];
public static string[] SplitValue(string value, char delim)
{
@@ -292,51 +307,101 @@ namespace MediaBrowser.Api
return result;
}
protected string GetPathValue(int index)
/// <summary>
/// Gets the path segment at the specified index.
/// </summary>
/// <param name="index">The index of the path segment.</param>
/// <returns>The path segment at the specified index.</returns>
/// <exception cref="IndexOutOfRangeException" >Path doesn't contain enough segments.</exception>
/// <exception cref="InvalidDataException" >Path doesn't start with the base url.</exception>
protected internal ReadOnlySpan<char> GetPathValue(int index)
{
var pathInfo = Parse(Request.PathInfo);
var first = pathInfo[0];
string baseUrl = ApiEntryPoint.Instance.ConfigurationManager.Configuration.BaseUrl;
// backwards compatibility
if (baseUrl.Length == 0)
static void ThrowIndexOutOfRangeException()
{
if (string.Equals(first, "mediabrowser", StringComparison.OrdinalIgnoreCase)
|| string.Equals(first, "emby", StringComparison.OrdinalIgnoreCase))
{
index++;
}
throw new IndexOutOfRangeException("Path doesn't contain enough segments.");
}
else if (string.Equals(first, baseUrl.Remove(0, 1)))
static void ThrowInvalidDataException()
{
index++;
var second = pathInfo[1];
if (string.Equals(second, "mediabrowser", StringComparison.OrdinalIgnoreCase)
|| string.Equals(second, "emby", StringComparison.OrdinalIgnoreCase))
throw new InvalidDataException("Path doesn't start with the base url.");
}
ReadOnlySpan<char> path = Request.PathInfo;
// Remove the protocol part from the url
int pos = path.LastIndexOf("://");
if (pos != -1)
{
path = path.Slice(pos + 3);
}
// Remove the query string
pos = path.LastIndexOf('?');
if (pos != -1)
{
path = path.Slice(0, pos);
}
// Remove the domain
pos = path.IndexOf('/');
if (pos != -1)
{
path = path.Slice(pos);
}
// Remove base url
string baseUrl = ServerConfigurationManager.Configuration.BaseUrl;
int baseUrlLen = baseUrl.Length;
if (baseUrlLen != 0)
{
if (path.StartsWith(baseUrl, StringComparison.OrdinalIgnoreCase))
{
index++;
path = path.Slice(baseUrlLen);
}
else
{
// The path doesn't start with the base url,
// how did we get here?
ThrowInvalidDataException();
}
}
return pathInfo[index];
}
// Remove leading /
path = path.Slice(1);
private static string[] Parse(string pathUri)
{
var actionParts = pathUri.Split(new[] { "://" }, StringSplitOptions.None);
var pathInfo = actionParts[actionParts.Length - 1];
var optionsPos = pathInfo.LastIndexOf('?');
if (optionsPos != -1)
// Backwards compatibility
const string Emby = "emby/";
if (path.StartsWith(Emby, StringComparison.OrdinalIgnoreCase))
{
pathInfo = pathInfo.Substring(0, optionsPos);
path = path.Slice(Emby.Length);
}
var args = pathInfo.Split('/');
const string MediaBrowser = "mediabrowser/";
if (path.StartsWith(MediaBrowser, StringComparison.OrdinalIgnoreCase))
{
path = path.Slice(MediaBrowser.Length);
}
return args.Skip(1).ToArray();
// Skip segments until we are at the right index
for (int i = 0; i < index; i++)
{
pos = path.IndexOf('/');
if (pos == -1)
{
ThrowIndexOutOfRangeException();
}
path = path.Slice(pos + 1);
}
// Remove the rest
pos = path.IndexOf('/');
if (pos != -1)
{
path = path.Slice(0, pos);
}
return path;
}
/// <summary>