limit access to response stream

This commit is contained in:
Luke Pulverenti 2016-11-12 02:14:04 -05:00
parent c035f2baa1
commit a855864207
5 changed files with 32 additions and 56 deletions

View File

@ -9,6 +9,7 @@ using System.Collections.Generic;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
using System.Reflection; using System.Reflection;
using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
using Emby.Server.Implementations.HttpServer; using Emby.Server.Implementations.HttpServer;
using Emby.Server.Implementations.HttpServer.SocketSharp; using Emby.Server.Implementations.HttpServer.SocketSharp;
@ -248,9 +249,7 @@ namespace Emby.Server.Implementations.HttpServer
httpRes.StatusCode = statusCode; httpRes.StatusCode = statusCode;
httpRes.ContentType = "text/html"; httpRes.ContentType = "text/html";
httpRes.Write(ex.Message); Write(httpRes, ex.Message);
httpRes.Close();
} }
catch catch
{ {
@ -404,7 +403,7 @@ namespace Emby.Server.Implementations.HttpServer
{ {
httpRes.StatusCode = 400; httpRes.StatusCode = 400;
httpRes.ContentType = "text/plain"; httpRes.ContentType = "text/plain";
httpRes.Write("Invalid host"); Write(httpRes, "Invalid host");
return; return;
} }
@ -458,7 +457,7 @@ namespace Emby.Server.Implementations.HttpServer
if (!string.Equals(newUrl, urlString, StringComparison.OrdinalIgnoreCase)) if (!string.Equals(newUrl, urlString, StringComparison.OrdinalIgnoreCase))
{ {
httpRes.Write( Write(httpRes,
"<!doctype html><html><head><title>Emby</title></head><body>Please update your Emby bookmark to <a href=\"" + "<!doctype html><html><head><title>Emby</title></head><body>Please update your Emby bookmark to <a href=\"" +
newUrl + "\">" + newUrl + "</a></body></html>"); newUrl + "\">" + newUrl + "</a></body></html>");
return; return;
@ -475,7 +474,7 @@ namespace Emby.Server.Implementations.HttpServer
if (!string.Equals(newUrl, urlString, StringComparison.OrdinalIgnoreCase)) if (!string.Equals(newUrl, urlString, StringComparison.OrdinalIgnoreCase))
{ {
httpRes.Write( Write(httpRes,
"<!doctype html><html><head><title>Emby</title></head><body>Please update your Emby bookmark to <a href=\"" + "<!doctype html><html><head><title>Emby</title></head><body>Please update your Emby bookmark to <a href=\"" +
newUrl + "\">" + newUrl + "</a></body></html>"); newUrl + "\">" + newUrl + "</a></body></html>");
return; return;
@ -513,7 +512,7 @@ namespace Emby.Server.Implementations.HttpServer
{ {
httpRes.StatusCode = 503; httpRes.StatusCode = 503;
httpRes.ContentType = "text/html"; httpRes.ContentType = "text/html";
httpRes.Write(GlobalResponse); Write(httpRes, GlobalResponse);
return; return;
} }
@ -547,6 +546,15 @@ namespace Emby.Server.Implementations.HttpServer
} }
} }
private void Write(IResponse response, string text)
{
var bOutput = Encoding.UTF8.GetBytes(text);
response.SetContentLength(bOutput.Length);
var outputStream = response.OutputStream;
outputStream.Write(bOutput, 0, bOutput.Length);
}
public static void RedirectToUrl(IResponse httpRes, string url) public static void RedirectToUrl(IResponse httpRes, string url)
{ {
httpRes.StatusCode = 302; httpRes.StatusCode = 302;

View File

@ -77,16 +77,6 @@ namespace Emby.Server.Implementations.HttpServer.SocketSharp
get { return _response.OutputStream; } get { return _response.OutputStream; }
} }
public void Write(string text)
{
var bOutput = System.Text.Encoding.UTF8.GetBytes(text);
_response.ContentLength64 = bOutput.Length;
var outputStream = _response.OutputStream;
outputStream.Write(bOutput, 0, bOutput.Length);
Close();
}
public void Close() public void Close()
{ {
if (!this.IsClosed) if (!this.IsClosed)
@ -108,8 +98,10 @@ namespace Emby.Server.Implementations.HttpServer.SocketSharp
{ {
try try
{ {
response.OutputStream.Flush(); var outputStream = response.OutputStream;
response.OutputStream.Dispose();
outputStream.Flush();
outputStream.Dispose();
response.Close(); response.Close();
} }
catch (Exception ex) catch (Exception ex)
@ -118,11 +110,6 @@ namespace Emby.Server.Implementations.HttpServer.SocketSharp
} }
} }
public void Flush()
{
_response.OutputStream.Flush();
}
public bool IsClosed public bool IsClosed
{ {
get; get;

View File

@ -136,23 +136,12 @@ namespace MediaBrowser.Model.Services
Stream OutputStream { get; } Stream OutputStream { get; }
/// <summary>
/// Write once to the Response Stream then close it.
/// </summary>
/// <param name="text"></param>
void Write(string text);
/// <summary> /// <summary>
/// Signal that this response has been handled and no more processing should be done. /// Signal that this response has been handled and no more processing should be done.
/// When used in a request or response filter, no more filters or processing is done on this request. /// When used in a request or response filter, no more filters or processing is done on this request.
/// </summary> /// </summary>
void Close(); void Close();
/// <summary>
/// Response.Flush() and OutputStream.Flush() seem to have different behaviour in ASP.NET
/// </summary>
void Flush();
/// <summary> /// <summary>
/// Gets a value indicating whether this instance is closed. /// Gets a value indicating whether this instance is closed.
/// </summary> /// </summary>
@ -160,8 +149,6 @@ namespace MediaBrowser.Model.Services
void SetContentLength(long contentLength); void SetContentLength(long contentLength);
bool KeepAlive { get; set; }
//Add Metadata to Response //Add Metadata to Response
Dictionary<string, object> Items { get; } Dictionary<string, object> Items { get; }
} }

View File

@ -18,15 +18,7 @@ namespace ServiceStack.Host
serializer(response, responseStream); serializer(response, responseStream);
} }
public Action<object, IResponse> GetResponseSerializer(string contentType) private Action<object, Stream> GetStreamSerializer(string contentType)
{
var serializer = GetStreamSerializer(contentType);
if (serializer == null) return null;
return (dto, httpRes) => serializer(dto, httpRes.OutputStream);
}
public Action<object, Stream> GetStreamSerializer(string contentType)
{ {
switch (GetRealContentType(contentType)) switch (GetRealContentType(contentType))
{ {

View File

@ -6,6 +6,7 @@ using System.IO;
using System.Net; using System.Net;
using System.Threading.Tasks; using System.Threading.Tasks;
using System.Collections.Generic; using System.Collections.Generic;
using System.Text;
using System.Threading; using System.Threading;
using MediaBrowser.Model.Services; using MediaBrowser.Model.Services;
using ServiceStack.Host; using ServiceStack.Host;
@ -14,19 +15,19 @@ namespace ServiceStack
{ {
public static class HttpResponseExtensionsInternal public static class HttpResponseExtensionsInternal
{ {
public static async Task<bool> WriteToOutputStream(IResponse response, object result) public static async Task<bool> WriteToOutputStream(IResponse response, Stream outputStream, object result)
{ {
var asyncStreamWriter = result as IAsyncStreamWriter; var asyncStreamWriter = result as IAsyncStreamWriter;
if (asyncStreamWriter != null) if (asyncStreamWriter != null)
{ {
await asyncStreamWriter.WriteToAsync(response.OutputStream, CancellationToken.None).ConfigureAwait(false); await asyncStreamWriter.WriteToAsync(outputStream, CancellationToken.None).ConfigureAwait(false);
return true; return true;
} }
var streamWriter = result as IStreamWriter; var streamWriter = result as IStreamWriter;
if (streamWriter != null) if (streamWriter != null)
{ {
streamWriter.WriteTo(response.OutputStream); streamWriter.WriteTo(outputStream);
return true; return true;
} }
@ -35,7 +36,7 @@ namespace ServiceStack
{ {
using (stream) using (stream)
{ {
await stream.CopyToAsync(response.OutputStream).ConfigureAwait(false); await stream.CopyToAsync(outputStream).ConfigureAwait(false);
return true; return true;
} }
} }
@ -46,7 +47,7 @@ namespace ServiceStack
response.ContentType = "application/octet-stream"; response.ContentType = "application/octet-stream";
response.SetContentLength(bytes.Length); response.SetContentLength(bytes.Length);
await response.OutputStream.WriteAsync(bytes, 0, bytes.Length).ConfigureAwait(false); await outputStream.WriteAsync(bytes, 0, bytes.Length).ConfigureAwait(false);
return true; return true;
} }
@ -151,10 +152,11 @@ namespace ServiceStack
response.ContentType += "; charset=utf-8"; response.ContentType += "; charset=utf-8";
} }
var writeToOutputStreamResult = await WriteToOutputStream(response, result).ConfigureAwait(false); var outputStream = response.OutputStream;
var writeToOutputStreamResult = await WriteToOutputStream(response, outputStream, result).ConfigureAwait(false);
if (writeToOutputStreamResult) if (writeToOutputStreamResult)
{ {
response.Flush(); //required for Compression
return; return;
} }
@ -164,12 +166,12 @@ namespace ServiceStack
if (response.ContentType == null || response.ContentType == "text/html") if (response.ContentType == null || response.ContentType == "text/html")
response.ContentType = defaultContentType; response.ContentType = defaultContentType;
response.Write(responseText); var bytes = Encoding.UTF8.GetBytes(responseText);
await outputStream.WriteAsync(bytes, 0, bytes.Length).ConfigureAwait(false);
return; return;
} }
var serializer = ContentTypes.Instance.GetResponseSerializer(defaultContentType); ContentTypes.Instance.SerializeToStream(request, result, outputStream);
serializer(result, response);
} }
} }
} }