161 lines
5.7 KiB
C#
161 lines
5.7 KiB
C#
#if (!UNITY_WEBGL || UNITY_EDITOR) && !BESTHTTP_DISABLE_ALTERNATE_SSL
|
|
|
|
using System;
|
|
using System.Collections.Generic;
|
|
|
|
using Best.HTTP.Response;
|
|
using Best.HTTP.Response.Decompression;
|
|
using Best.HTTP.Shared;
|
|
using Best.HTTP.Shared.PlatformSupport.Memory;
|
|
|
|
namespace Best.HTTP.Hosts.Connections.HTTP2
|
|
{
|
|
public sealed class HTTP2Response : HTTPResponse
|
|
{
|
|
// For progress report
|
|
public long ExpectedContentLength { get; private set; }
|
|
|
|
private string contentEncoding = null;
|
|
|
|
bool isPrepared;
|
|
private IDecompressor _decompressor;
|
|
|
|
public HTTP2Response(HTTPRequest request, bool isFromCache)
|
|
: base(request, isFromCache)
|
|
{
|
|
this.HTTPVersion = new Version(2, 0);
|
|
}
|
|
|
|
internal void AddHeaders(List<KeyValuePair<string, string>> headers)
|
|
{
|
|
this.ExpectedContentLength = -1;
|
|
Dictionary<string, List<string>> newHeaders = this.Request.DownloadSettings.OnHeadersReceived != null ? new Dictionary<string, List<string>>() : null;
|
|
|
|
for (int i = 0; i < headers.Count; ++i)
|
|
{
|
|
KeyValuePair<string, string> header = headers[i];
|
|
|
|
if (header.Key.Equals(":status", StringComparison.Ordinal))
|
|
{
|
|
base.StatusCode = int.Parse(header.Value);
|
|
base.Message = string.Empty;
|
|
}
|
|
else
|
|
{
|
|
if (string.IsNullOrEmpty(this.contentEncoding) && header.Key.Equals("content-encoding", StringComparison.OrdinalIgnoreCase))
|
|
{
|
|
this.contentEncoding = header.Value;
|
|
}
|
|
else if (base.Request.DownloadSettings.OnDownloadProgress != null && header.Key.Equals("content-length", StringComparison.OrdinalIgnoreCase))
|
|
{
|
|
long contentLength;
|
|
if (long.TryParse(header.Value, out contentLength))
|
|
this.ExpectedContentLength = contentLength;
|
|
else
|
|
HTTPManager.Logger.Information("HTTP2Response", string.Format("AddHeaders - Can't parse Content-Length as an int: '{0}'", header.Value), this.Context);
|
|
}
|
|
|
|
base.AddHeader(header.Key, header.Value);
|
|
}
|
|
|
|
if (newHeaders != null)
|
|
{
|
|
List<string> values;
|
|
if (!newHeaders.TryGetValue(header.Key, out values))
|
|
newHeaders.Add(header.Key, values = new List<string>(1));
|
|
|
|
values.Add(header.Value);
|
|
}
|
|
}
|
|
|
|
if (this.ExpectedContentLength == -1 && base.Request.DownloadSettings.OnDownloadProgress != null)
|
|
HTTPManager.Logger.Information("HTTP2Response", "AddHeaders - No Content-Length header found!", this.Context);
|
|
|
|
RequestEventHelper.EnqueueRequestEvent(new RequestEventInfo(this.Request, newHeaders));
|
|
}
|
|
|
|
internal void Prepare(IDownloadContentBufferAvailable bufferAvailable)
|
|
{
|
|
if (!this.isPrepared)
|
|
{
|
|
this.isPrepared = true;
|
|
|
|
CreateDownloadStream(bufferAvailable);
|
|
|
|
base.BeginReceiveContent();
|
|
}
|
|
}
|
|
|
|
internal void ProcessData(BufferSegment payload)
|
|
{
|
|
// https://github.com/Benedicht/BestHTTP-Issues/issues/183
|
|
// If _decompressor is still null, remove the content encoding value and serve the content as-is.
|
|
if (!string.IsNullOrEmpty(this.contentEncoding) && this._decompressor == null)
|
|
{
|
|
if ((this._decompressor = DecompressorFactory.GetDecompressor(this.contentEncoding, this.Context)) == null)
|
|
this.contentEncoding = null;
|
|
}
|
|
|
|
if (!string.IsNullOrEmpty(this.contentEncoding))
|
|
{
|
|
BufferSegment result = BufferSegment.Empty;
|
|
bool release;
|
|
try
|
|
{
|
|
(result, release) = this._decompressor.Decompress(payload, false, true, this.Context);
|
|
}
|
|
catch
|
|
{
|
|
BufferPool.Release(payload);
|
|
throw;
|
|
}
|
|
if (release)
|
|
BufferPool.Release(payload);
|
|
|
|
base.FeedDownloadedContentChunk(result);
|
|
}
|
|
else
|
|
base.FeedDownloadedContentChunk(payload);
|
|
}
|
|
|
|
internal void FinishProcessData()
|
|
{
|
|
if (this._decompressor != null)
|
|
{
|
|
var (decompressed, _) = this._decompressor.Decompress(BufferSegment.Empty, true, true, this.Context);
|
|
if (decompressed != BufferSegment.Empty)
|
|
base.FeedDownloadedContentChunk(decompressed);
|
|
|
|
this._decompressor.Dispose();
|
|
this._decompressor = null;
|
|
}
|
|
|
|
base.FinishedContentReceiving();
|
|
}
|
|
|
|
protected override void Dispose(bool disposing)
|
|
{
|
|
base.Dispose(disposing);
|
|
|
|
if (disposing)
|
|
{
|
|
if (this._decompressor != null)
|
|
{
|
|
// In some cases, the request is aborted and the decompressor left in an incomplete state.
|
|
// Closing it might cause an exception that we don't care about.
|
|
try
|
|
{
|
|
this._decompressor.Dispose();
|
|
}
|
|
catch
|
|
{ }
|
|
|
|
this._decompressor = null;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
#endif
|