This commit is contained in:
LukePulverenti Luke Pulverenti luke pulverenti
2012-08-19 16:38:47 -04:00
38 changed files with 393 additions and 373 deletions

View File

@@ -2,17 +2,16 @@
using System.Collections.Generic;
using System.ComponentModel.Composition;
using System.ComponentModel.Composition.Hosting;
using System.Configuration;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Threading.Tasks;
using MediaBrowser.Common.Configuration;
using MediaBrowser.Common.Logging;
using MediaBrowser.Common.Net;
using MediaBrowser.Common.Plugins;
using MediaBrowser.Common.Serialization;
using MediaBrowser.Model.Progress;
using System.Threading.Tasks;
namespace MediaBrowser.Common.Kernel
{
@@ -93,6 +92,8 @@ namespace MediaBrowser.Common.Kernel
/// </summary>
protected void ReloadComposableParts()
{
DisposeComposableParts();
// Gets all plugin assemblies by first reading all bytes of the .dll and calling Assembly.Load against that
// This will prevent the .dll file from getting locked, and allow us to replace it when needed
IEnumerable<Assembly> pluginAssemblies = Directory.GetFiles(ApplicationPaths.PluginsPath, "*.dll", SearchOption.AllDirectories).Select(f => Assembly.Load(File.ReadAllBytes((f))));
@@ -203,10 +204,33 @@ namespace MediaBrowser.Common.Kernel
/// </summary>
public virtual void Dispose()
{
DisposeComposableParts();
DisposeHttpServer();
DisposeLogger();
}
/// <summary>
/// Disposes all objects gathered through MEF composable parts
/// </summary>
protected virtual void DisposeComposableParts()
{
DisposePlugins();
}
/// <summary>
/// Disposes all plugins
/// </summary>
private void DisposePlugins()
{
if (Plugins != null)
{
foreach (BasePlugin plugin in Plugins)
{
plugin.Dispose();
}
}
}
/// <summary>
/// Disposes the current HttpServer
/// </summary>

View File

@@ -14,9 +14,9 @@ namespace MediaBrowser.Common.Net.Handlers
protected string ResourcePath { get; set; }
public override string ContentType
public override Task<string> GetContentType()
{
get
return Task.Run(() =>
{
string extension = Path.GetExtension(ResourcePath);
@@ -46,7 +46,7 @@ namespace MediaBrowser.Common.Net.Handlers
}
return "text/plain; charset=utf-8";
}
});
}
protected override Task WriteResponseToOutputStream(Stream stream)

View File

@@ -111,7 +111,7 @@ namespace MediaBrowser.Common.Net.Handlers
/// <summary>
/// Gets the MIME type to include in the response headers
/// </summary>
public abstract string ContentType { get; }
public abstract Task<string> GetContentType();
/// <summary>
/// Gets the status code to include in the response headers
@@ -129,31 +129,9 @@ namespace MediaBrowser.Common.Net.Handlers
}
}
private bool _LastDateModifiedDiscovered = false;
private DateTime? _LastDateModified = null;
/// <summary>
/// Gets the last date modified of the content being returned, if this can be determined.
/// This will be used to invalidate the cache, so it's not needed if CacheDuration is 0.
/// </summary>
public DateTime? LastDateModified
public virtual bool ShouldCompressResponse(string contentType)
{
get
{
if (!_LastDateModifiedDiscovered)
{
_LastDateModified = GetLastDateModified();
}
return _LastDateModified;
}
}
public virtual bool CompressResponse
{
get
{
return true;
}
return true;
}
private bool ClientSupportsCompression
@@ -207,10 +185,12 @@ namespace MediaBrowser.Common.Net.Handlers
// When serving a range request, we need to return status code 206 to indicate a partial response body
StatusCode = SupportsByteRangeRequests && IsRangeRequest ? 206 : 200;
ctx.Response.ContentType = ContentType;
ctx.Response.ContentType = await GetContentType();
TimeSpan cacheDuration = CacheDuration;
DateTime? lastDateModified = await GetLastDateModified();
if (ctx.Request.Headers.AllKeys.Contains("If-Modified-Since"))
{
DateTime ifModifiedSince;
@@ -218,18 +198,20 @@ namespace MediaBrowser.Common.Net.Handlers
if (DateTime.TryParse(ctx.Request.Headers["If-Modified-Since"].Replace(" GMT", string.Empty), out ifModifiedSince))
{
// If the cache hasn't expired yet just return a 304
if (IsCacheValid(ifModifiedSince, cacheDuration, LastDateModified))
if (IsCacheValid(ifModifiedSince, cacheDuration, lastDateModified))
{
StatusCode = 304;
}
}
}
PrepareResponse();
await PrepareResponse();
if (IsResponseValid)
{
await ProcessUncachedRequest(ctx, cacheDuration);
bool compressResponse = ShouldCompressResponse(ctx.Response.ContentType) && ClientSupportsCompression;
await ProcessUncachedRequest(ctx, compressResponse, cacheDuration, lastDateModified);
}
else
{
@@ -241,7 +223,7 @@ namespace MediaBrowser.Common.Net.Handlers
{
// It might be too late if some response data has already been transmitted, but try to set this
ctx.Response.StatusCode = 500;
Logger.LogException(ex);
}
finally
@@ -250,7 +232,7 @@ namespace MediaBrowser.Common.Net.Handlers
}
}
private async Task ProcessUncachedRequest(HttpListenerContext ctx, TimeSpan cacheDuration)
private async Task ProcessUncachedRequest(HttpListenerContext ctx, bool compressResponse, TimeSpan cacheDuration, DateTime? lastDateModified)
{
long? totalContentLength = TotalContentLength;
@@ -270,7 +252,7 @@ namespace MediaBrowser.Common.Net.Handlers
}
// Add the compression header
if (CompressResponse && ClientSupportsCompression)
if (compressResponse)
{
ctx.Response.AddHeader("Content-Encoding", CompressionMethod);
}
@@ -278,7 +260,7 @@ namespace MediaBrowser.Common.Net.Handlers
// Add caching headers
if (cacheDuration.Ticks > 0)
{
CacheResponse(ctx.Response, cacheDuration, LastDateModified);
CacheResponse(ctx.Response, cacheDuration, lastDateModified);
}
// Set the status code
@@ -289,7 +271,7 @@ namespace MediaBrowser.Common.Net.Handlers
// Finally, write the response data
Stream outputStream = ctx.Response.OutputStream;
if (CompressResponse && ClientSupportsCompression)
if (compressResponse)
{
if (CompressionMethod.Equals("deflate", StringComparison.OrdinalIgnoreCase))
{
@@ -321,10 +303,11 @@ namespace MediaBrowser.Common.Net.Handlers
}
/// <summary>
/// Gives subclasses a chance to do and prep work, and also to validate data and set an error status code, if needed
/// Gives subclasses a chance to do any prep work, and also to validate data and set an error status code, if needed
/// </summary>
protected virtual void PrepareResponse()
protected virtual Task PrepareResponse()
{
return Task.Run(() => { });
}
protected abstract Task WriteResponseToOutputStream(Stream stream);
@@ -372,9 +355,11 @@ namespace MediaBrowser.Common.Net.Handlers
return null;
}
protected virtual DateTime? GetLastDateModified()
protected virtual Task<DateTime?> GetLastDateModified()
{
return null;
DateTime? value = null;
return Task.Run<DateTime?>(() => { return value; });
}
private bool IsResponseValid

View File

@@ -6,19 +6,22 @@ namespace MediaBrowser.Common.Net.Handlers
{
public abstract class BaseJsonHandler<T> : BaseHandler
{
public override string ContentType
public override Task<string> GetContentType()
{
get { return MimeTypes.JsonMimeType; }
return Task.Run(() =>
{
return MimeTypes.JsonMimeType;
});
}
private bool _ObjectToSerializeEnsured = false;
private T _ObjectToSerialize;
private void EnsureObjectToSerialize()
private async Task EnsureObjectToSerialize()
{
if (!_ObjectToSerializeEnsured)
{
_ObjectToSerialize = GetObjectToSerialize();
_ObjectToSerialize = await GetObjectToSerialize();
if (_ObjectToSerialize == null)
{
@@ -29,30 +32,18 @@ namespace MediaBrowser.Common.Net.Handlers
}
}
private T ObjectToSerialize
protected abstract Task<T> GetObjectToSerialize();
protected override async Task PrepareResponse()
{
get
{
EnsureObjectToSerialize();
return _ObjectToSerialize;
}
await EnsureObjectToSerialize();
}
protected abstract T GetObjectToSerialize();
protected override void PrepareResponse()
protected async override Task WriteResponseToOutputStream(Stream stream)
{
base.PrepareResponse();
await EnsureObjectToSerialize();
EnsureObjectToSerialize();
}
protected override Task WriteResponseToOutputStream(Stream stream)
{
return Task.Run(() =>
{
JsonSerializer.SerializeToStream<T>(ObjectToSerialize, stream);
});
JsonSerializer.SerializeToStream<T>(_ObjectToSerialize, stream);
}
}
}

View File

@@ -77,27 +77,22 @@ namespace MediaBrowser.Common.Net.Handlers
}
}
public override bool CompressResponse
public override bool ShouldCompressResponse(string contentType)
{
get
// Can't compress these
if (IsRangeRequest)
{
// Can't compress these
if (IsRangeRequest)
{
return false;
}
string contentType = ContentType;
// Don't compress media
if (contentType.StartsWith("audio/", StringComparison.OrdinalIgnoreCase) || contentType.StartsWith("video/", StringComparison.OrdinalIgnoreCase))
{
return false;
}
// It will take some work to support compression within this handler
return false;
}
// Don't compress media
if (contentType.StartsWith("audio/", StringComparison.OrdinalIgnoreCase) || contentType.StartsWith("video/", StringComparison.OrdinalIgnoreCase))
{
return false;
}
// It will take some work to support compression within this handler
return false;
}
protected override long? GetTotalContentLength()
@@ -105,31 +100,32 @@ namespace MediaBrowser.Common.Net.Handlers
return SourceStream.Length;
}
protected override DateTime? GetLastDateModified()
protected override Task<DateTime?> GetLastDateModified()
{
EnsureSourceStream();
if (SourceStream == null)
return Task.Run<DateTime?>(() =>
{
return null;
}
EnsureSourceStream();
return File.GetLastWriteTime(Path);
if (SourceStream == null)
{
return null;
}
return File.GetLastWriteTime(Path);
});
}
public override string ContentType
public override Task<string> GetContentType()
{
get
return Task.Run(() =>
{
return MimeTypes.GetMimeType(Path);
}
});
}
protected override void PrepareResponse()
protected override Task PrepareResponse()
{
base.PrepareResponse();
EnsureSourceStream();
return Task.Run(() => { EnsureSourceStream(); });
}
protected async override Task WriteResponseToOutputStream(Stream stream)