From d8c01ded6eb57ba312e1cd62c4fa51dbcce6053a Mon Sep 17 00:00:00 2001 From: LukePulverenti Luke Pulverenti luke pulverenti Date: Wed, 19 Sep 2012 12:51:37 -0400 Subject: made some improvements to the base http handler --- .../Net/Handlers/BaseEmbeddedResourceHandler.cs | 5 - MediaBrowser.Common/Net/Handlers/BaseHandler.cs | 146 +++++++++------------ .../Net/Handlers/BaseSerializationHandler.cs | 84 ++++++------ .../Net/Handlers/StaticFileHandler.cs | 87 +++++------- 4 files changed, 131 insertions(+), 191 deletions(-) (limited to 'MediaBrowser.Common/Net') diff --git a/MediaBrowser.Common/Net/Handlers/BaseEmbeddedResourceHandler.cs b/MediaBrowser.Common/Net/Handlers/BaseEmbeddedResourceHandler.cs index 3ce85a688d..579e341fec 100644 --- a/MediaBrowser.Common/Net/Handlers/BaseEmbeddedResourceHandler.cs +++ b/MediaBrowser.Common/Net/Handlers/BaseEmbeddedResourceHandler.cs @@ -13,11 +13,6 @@ namespace MediaBrowser.Common.Net.Handlers protected string ResourcePath { get; set; } - public override Task GetContentType() - { - return Task.FromResult(MimeTypes.GetMimeType(ResourcePath)); - } - protected override Task WriteResponseToOutputStream(Stream stream) { return GetEmbeddedResourceStream().CopyToAsync(stream); diff --git a/MediaBrowser.Common/Net/Handlers/BaseHandler.cs b/MediaBrowser.Common/Net/Handlers/BaseHandler.cs index ab12cb2cf2..a5058e6caf 100644 --- a/MediaBrowser.Common/Net/Handlers/BaseHandler.cs +++ b/MediaBrowser.Common/Net/Handlers/BaseHandler.cs @@ -112,32 +112,6 @@ namespace MediaBrowser.Common.Net.Handlers } } - /// - /// Gets the MIME type to include in the response headers - /// - public abstract Task GetContentType(); - - /// - /// Gets the status code to include in the response headers - /// - protected int StatusCode { get; set; } - - /// - /// Gets the cache duration to include in the response headers - /// - public virtual TimeSpan CacheDuration - { - get - { - return TimeSpan.FromTicks(0); - } - } - - public virtual bool ShouldCompressResponse(string contentType) - { - return true; - } - private bool ClientSupportsCompression { get @@ -186,22 +160,21 @@ namespace MediaBrowser.Common.Net.Handlers ctx.Response.Headers["Accept-Ranges"] = "bytes"; } - // Set the initial status code - // 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 = await GetContentType().ConfigureAwait(false); + ResponseInfo responseInfo = await GetResponseInfo().ConfigureAwait(false); - string etag = await GetETag().ConfigureAwait(false); - - if (!string.IsNullOrEmpty(etag)) + if (responseInfo.IsResponseValid) { - ctx.Response.Headers["ETag"] = etag; + // Set the initial status code + // When serving a range request, we need to return status code 206 to indicate a partial response body + responseInfo.StatusCode = SupportsByteRangeRequests && IsRangeRequest ? 206 : 200; } - TimeSpan cacheDuration = CacheDuration; + ctx.Response.ContentType = responseInfo.ContentType; - DateTime? lastDateModified = await GetLastDateModified().ConfigureAwait(false); + if (!string.IsNullOrEmpty(responseInfo.Etag)) + { + ctx.Response.Headers["ETag"] = responseInfo.Etag; + } if (ctx.Request.Headers.AllKeys.Contains("If-Modified-Since")) { @@ -210,30 +183,26 @@ namespace MediaBrowser.Common.Net.Handlers if (DateTime.TryParse(ctx.Request.Headers["If-Modified-Since"], out ifModifiedSince)) { // If the cache hasn't expired yet just return a 304 - if (IsCacheValid(ifModifiedSince.ToUniversalTime(), cacheDuration, lastDateModified)) + if (IsCacheValid(ifModifiedSince.ToUniversalTime(), responseInfo.CacheDuration, responseInfo.DateLastModified)) { // ETag must also match (if supplied) - if ((etag ?? string.Empty).Equals(ctx.Request.Headers["If-None-Match"] ?? string.Empty)) + if ((responseInfo.Etag ?? string.Empty).Equals(ctx.Request.Headers["If-None-Match"] ?? string.Empty)) { - StatusCode = 304; + responseInfo.StatusCode = 304; } } } } - await PrepareResponse().ConfigureAwait(false); - - Logger.LogInfo("Responding with status code {0} for url {1}", StatusCode, url); + Logger.LogInfo("Responding with status code {0} for url {1}", responseInfo.StatusCode, url); - if (IsResponseValid) + if (responseInfo.IsResponseValid) { - bool compressResponse = ShouldCompressResponse(ctx.Response.ContentType) && ClientSupportsCompression; - - await ProcessUncachedRequest(ctx, compressResponse, cacheDuration, lastDateModified).ConfigureAwait(false); + await ProcessUncachedRequest(ctx, responseInfo).ConfigureAwait(false); } else { - ctx.Response.StatusCode = StatusCode; + ctx.Response.StatusCode = responseInfo.StatusCode; ctx.Response.SendChunked = false; } } @@ -250,7 +219,7 @@ namespace MediaBrowser.Common.Net.Handlers } } - private async Task ProcessUncachedRequest(HttpListenerContext ctx, bool compressResponse, TimeSpan cacheDuration, DateTime? lastDateModified) + private async Task ProcessUncachedRequest(HttpListenerContext ctx, ResponseInfo responseInfo) { long? totalContentLength = TotalContentLength; @@ -269,22 +238,29 @@ namespace MediaBrowser.Common.Net.Handlers ctx.Response.ContentLength64 = totalContentLength.Value; } + var compressResponse = responseInfo.CompressResponse && ClientSupportsCompression; + // Add the compression header if (compressResponse) { ctx.Response.AddHeader("Content-Encoding", CompressionMethod); } + if (responseInfo.DateLastModified.HasValue) + { + ctx.Response.Headers[HttpResponseHeader.LastModified] = responseInfo.DateLastModified.Value.ToString("r"); + } + // Add caching headers - if (cacheDuration.Ticks > 0) + if (responseInfo.CacheDuration.Ticks > 0) { - CacheResponse(ctx.Response, cacheDuration, lastDateModified); + CacheResponse(ctx.Response, responseInfo.CacheDuration); } // Set the status code - ctx.Response.StatusCode = StatusCode; + ctx.Response.StatusCode = responseInfo.StatusCode; - if (IsResponseValid) + if (responseInfo.IsResponseValid) { // Finally, write the response data Stream outputStream = ctx.Response.OutputStream; @@ -311,28 +287,10 @@ namespace MediaBrowser.Common.Net.Handlers } } - private void CacheResponse(HttpListenerResponse response, TimeSpan duration, DateTime? dateModified) + private void CacheResponse(HttpListenerResponse response, TimeSpan duration) { - DateTime now = DateTime.UtcNow; - - DateTime lastModified = dateModified ?? now; - response.Headers[HttpResponseHeader.CacheControl] = "public, max-age=" + Convert.ToInt32(duration.TotalSeconds); - response.Headers[HttpResponseHeader.Expires] = now.Add(duration).ToString("r"); - response.Headers[HttpResponseHeader.LastModified] = lastModified.ToString("r"); - } - - protected virtual Task GetETag() - { - return Task.FromResult(string.Empty); - } - - /// - /// Gives subclasses a chance to do any prep work, and also to validate data and set an error status code, if needed - /// - protected virtual Task PrepareResponse() - { - return Task.FromResult(null); + response.Headers[HttpResponseHeader.Expires] = DateTime.UtcNow.Add(duration).ToString("r"); } protected abstract Task WriteResponseToOutputStream(Stream stream); @@ -380,20 +338,7 @@ namespace MediaBrowser.Common.Net.Handlers return null; } - protected virtual Task GetLastDateModified() - { - DateTime? value = null; - - return Task.FromResult(value); - } - - private bool IsResponseValid - { - get - { - return StatusCode == 200 || StatusCode == 206; - } - } + protected abstract Task GetResponseInfo(); private Hashtable _formValues; @@ -455,4 +400,31 @@ namespace MediaBrowser.Common.Net.Handlers return formVars; } } + + public class ResponseInfo + { + public string ContentType { get; set; } + public string Etag { get; set; } + public DateTime? DateLastModified { get; set; } + public TimeSpan CacheDuration { get; set; } + public bool CompressResponse { get; set; } + public int StatusCode { get; set; } + + public ResponseInfo() + { + CacheDuration = TimeSpan.FromTicks(0); + + CompressResponse = true; + + StatusCode = 200; + } + + public bool IsResponseValid + { + get + { + return StatusCode == 200 || StatusCode == 206; + } + } + } } \ No newline at end of file diff --git a/MediaBrowser.Common/Net/Handlers/BaseSerializationHandler.cs b/MediaBrowser.Common/Net/Handlers/BaseSerializationHandler.cs index d60a9ae1f2..53b3ee817f 100644 --- a/MediaBrowser.Common/Net/Handlers/BaseSerializationHandler.cs +++ b/MediaBrowser.Common/Net/Handlers/BaseSerializationHandler.cs @@ -1,12 +1,12 @@ -using System; +using MediaBrowser.Common.Serialization; +using System; using System.IO; using System.Threading.Tasks; -using MediaBrowser.Common.Serialization; namespace MediaBrowser.Common.Net.Handlers { public abstract class BaseSerializationHandler : BaseHandler - where T : class + where T : class { public SerializationFormat SerializationFormat { @@ -22,61 +22,61 @@ namespace MediaBrowser.Common.Net.Handlers return (SerializationFormat)Enum.Parse(typeof(SerializationFormat), format, true); } } - - public override Task GetContentType() + + protected string ContentType { - switch (SerializationFormat) + get { - case SerializationFormat.Jsv: - return Task.FromResult("text/plain"); - case SerializationFormat.Protobuf: - return Task.FromResult("application/x-protobuf"); - default: - return Task.FromResult(MimeTypes.JsonMimeType); + switch (SerializationFormat) + { + case SerializationFormat.Jsv: + return "text/plain"; + case SerializationFormat.Protobuf: + return "application/x-protobuf"; + default: + return MimeTypes.JsonMimeType; + } } } - private bool _objectToSerializeEnsured; - private T _objectToSerialize; - - private async Task EnsureObjectToSerialize() + protected override async Task GetResponseInfo() { - if (!_objectToSerializeEnsured) + ResponseInfo info = new ResponseInfo { - _objectToSerialize = await GetObjectToSerialize().ConfigureAwait(false); + ContentType = ContentType + }; - if (_objectToSerialize == null) - { - StatusCode = 404; - } + _objectToSerialize = await GetObjectToSerialize().ConfigureAwait(false); - _objectToSerializeEnsured = true; + if (_objectToSerialize == null) + { + info.StatusCode = 404; } + + return info; } - protected abstract Task GetObjectToSerialize(); + private T _objectToSerialize; - protected override Task PrepareResponse() - { - return EnsureObjectToSerialize(); - } + protected abstract Task GetObjectToSerialize(); - protected async override Task WriteResponseToOutputStream(Stream stream) + protected override Task WriteResponseToOutputStream(Stream stream) { - await EnsureObjectToSerialize().ConfigureAwait(false); - - switch (SerializationFormat) + return Task.Run(() => { - case SerializationFormat.Jsv: - JsvSerializer.SerializeToStream(_objectToSerialize, stream); - break; - case SerializationFormat.Protobuf: - ProtobufSerializer.SerializeToStream(_objectToSerialize, stream); - break; - default: - JsonSerializer.SerializeToStream(_objectToSerialize, stream); - break; - } + switch (SerializationFormat) + { + case SerializationFormat.Jsv: + JsvSerializer.SerializeToStream(_objectToSerialize, stream); + break; + case SerializationFormat.Protobuf: + ProtobufSerializer.SerializeToStream(_objectToSerialize, stream); + break; + default: + JsonSerializer.SerializeToStream(_objectToSerialize, stream); + break; + } + }); } } diff --git a/MediaBrowser.Common/Net/Handlers/StaticFileHandler.cs b/MediaBrowser.Common/Net/Handlers/StaticFileHandler.cs index 741d2d6c17..11438b164b 100644 --- a/MediaBrowser.Common/Net/Handlers/StaticFileHandler.cs +++ b/MediaBrowser.Common/Net/Handlers/StaticFileHandler.cs @@ -33,46 +33,7 @@ namespace MediaBrowser.Common.Net.Handlers } } - private bool _sourceStreamEnsured; - private Stream _sourceStream; - private Stream SourceStream - { - get - { - EnsureSourceStream(); - return _sourceStream; - } - } - - private void EnsureSourceStream() - { - if (!_sourceStreamEnsured) - { - try - { - _sourceStream = File.OpenRead(Path); - } - catch (FileNotFoundException ex) - { - StatusCode = 404; - Logger.LogException(ex); - } - catch (DirectoryNotFoundException ex) - { - StatusCode = 404; - Logger.LogException(ex); - } - catch (UnauthorizedAccessException ex) - { - StatusCode = 403; - Logger.LogException(ex); - } - finally - { - _sourceStreamEnsured = true; - } - } - } + private Stream SourceStream { get; set; } protected override bool SupportsByteRangeRequests { @@ -82,7 +43,7 @@ namespace MediaBrowser.Common.Net.Handlers } } - public override bool ShouldCompressResponse(string contentType) + private bool ShouldCompressResponse(string contentType) { // Can't compress these if (IsRangeRequest) @@ -105,29 +66,41 @@ namespace MediaBrowser.Common.Net.Handlers return SourceStream.Length; } - protected override Task GetLastDateModified() + protected override Task GetResponseInfo() { - DateTime? value = null; - - EnsureSourceStream(); + ResponseInfo info = new ResponseInfo + { + ContentType = MimeTypes.GetMimeType(Path), + }; - if (SourceStream != null) + try + { + SourceStream = File.OpenRead(Path); + } + catch (FileNotFoundException ex) + { + info.StatusCode = 404; + Logger.LogException(ex); + } + catch (DirectoryNotFoundException ex) { - value = File.GetLastWriteTimeUtc(Path); + info.StatusCode = 404; + Logger.LogException(ex); + } + catch (UnauthorizedAccessException ex) + { + info.StatusCode = 403; + Logger.LogException(ex); } - return Task.FromResult(value); - } + info.CompressResponse = ShouldCompressResponse(info.ContentType); - public override Task GetContentType() - { - return Task.FromResult(MimeTypes.GetMimeType(Path)); - } + if (SourceStream != null) + { + info.DateLastModified = File.GetLastWriteTimeUtc(Path); + } - protected override Task PrepareResponse() - { - EnsureSourceStream(); - return Task.FromResult(null); + return Task.FromResult(info); } protected override Task WriteResponseToOutputStream(Stream stream) -- cgit v1.2.3