186 lines
5.8 KiB
C#
186 lines
5.8 KiB
C#
// Copyright (c) .NET Foundation. All rights reserved.
|
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
|
|
|
using System;
|
|
using System.IO;
|
|
using Microsoft.AspNetCore.Http;
|
|
|
|
namespace Microsoft.AspNetCore.ResponseCaching.Internal
|
|
{
|
|
internal static class DefaultResponseCacheSerializer
|
|
{
|
|
private const int FormatVersion = 1;
|
|
|
|
public static object Deserialize(byte[] serializedEntry)
|
|
{
|
|
using (var memory = new MemoryStream(serializedEntry))
|
|
{
|
|
using (var reader = new BinaryReader(memory))
|
|
{
|
|
return Read(reader);
|
|
}
|
|
}
|
|
}
|
|
|
|
public static byte[] Serialize(object entry)
|
|
{
|
|
using (var memory = new MemoryStream())
|
|
{
|
|
using (var writer = new BinaryWriter(memory))
|
|
{
|
|
Write(writer, entry);
|
|
writer.Flush();
|
|
return memory.ToArray();
|
|
}
|
|
}
|
|
}
|
|
|
|
// Serialization Format
|
|
// Format version (int)
|
|
// Type (char: 'R' for CachedResponse, 'V' for CachedVaryBy)
|
|
// Type-dependent data (see CachedResponse and CachedVaryBy)
|
|
public static object Read(BinaryReader reader)
|
|
{
|
|
if (reader == null)
|
|
{
|
|
throw new ArgumentNullException(nameof(reader));
|
|
}
|
|
|
|
if (reader.ReadInt32() != FormatVersion)
|
|
{
|
|
return null;
|
|
}
|
|
|
|
var type = reader.ReadChar();
|
|
|
|
if (type == 'R')
|
|
{
|
|
var cachedResponse = ReadCachedResponse(reader);
|
|
return cachedResponse;
|
|
}
|
|
else if (type == 'V')
|
|
{
|
|
var cachedResponse = ReadCachedVaryBy(reader);
|
|
return cachedResponse;
|
|
}
|
|
|
|
// Unable to read as CachedResponse or CachedVaryBy
|
|
return null;
|
|
}
|
|
|
|
// Serialization Format
|
|
// Creation time - UtcTicks (long)
|
|
// Status code (int)
|
|
// Header count (int)
|
|
// Header(s)
|
|
// Key (string)
|
|
// Value (string)
|
|
// Body length (int)
|
|
// Body (byte[])
|
|
private static CachedResponse ReadCachedResponse(BinaryReader reader)
|
|
{
|
|
var created = new DateTimeOffset(reader.ReadInt64(), TimeSpan.Zero);
|
|
var statusCode = reader.ReadInt32();
|
|
var headerCount = reader.ReadInt32();
|
|
var headers = new HeaderDictionary();
|
|
for (var index = 0; index < headerCount; index++)
|
|
{
|
|
var key = reader.ReadString();
|
|
var value = reader.ReadString();
|
|
headers[key] = value;
|
|
}
|
|
var bodyLength = reader.ReadInt32();
|
|
var body = reader.ReadBytes(bodyLength);
|
|
|
|
return new CachedResponse { Created = created, StatusCode = statusCode, Headers = headers, Body = body };
|
|
}
|
|
|
|
// Serialization Format
|
|
// Headers count
|
|
// Headers if count > 0 (comma separated string)
|
|
// Params count
|
|
// Params if count > 0 (comma separated string)
|
|
private static CachedVaryBy ReadCachedVaryBy(BinaryReader reader)
|
|
{
|
|
var headerCount = reader.ReadInt32();
|
|
var headers = new string[headerCount];
|
|
for (var index = 0; index < headerCount; index++)
|
|
{
|
|
headers[index] = reader.ReadString();
|
|
}
|
|
var paramCount = reader.ReadInt32();
|
|
var param = new string[paramCount];
|
|
for (var index = 0; index < paramCount; index++)
|
|
{
|
|
param[index] = reader.ReadString();
|
|
}
|
|
|
|
return new CachedVaryBy { Headers = headers, Params = param };
|
|
}
|
|
|
|
// See serialization format above
|
|
public static void Write(BinaryWriter writer, object entry)
|
|
{
|
|
if (writer == null)
|
|
{
|
|
throw new ArgumentNullException(nameof(writer));
|
|
}
|
|
|
|
if (entry == null)
|
|
{
|
|
throw new ArgumentNullException(nameof(entry));
|
|
}
|
|
|
|
writer.Write(FormatVersion);
|
|
|
|
if (entry is CachedResponse)
|
|
{
|
|
WriteCachedResponse(writer, entry as CachedResponse);
|
|
}
|
|
else if (entry is CachedVaryBy)
|
|
{
|
|
WriteCachedVaryBy(writer, entry as CachedVaryBy);
|
|
}
|
|
else
|
|
{
|
|
throw new NotSupportedException($"Unrecognized entry format for {nameof(entry)}.");
|
|
}
|
|
}
|
|
|
|
// See serialization format above
|
|
private static void WriteCachedResponse(BinaryWriter writer, CachedResponse entry)
|
|
{
|
|
writer.Write('R');
|
|
writer.Write(entry.Created.UtcTicks);
|
|
writer.Write(entry.StatusCode);
|
|
writer.Write(entry.Headers.Count);
|
|
foreach (var header in entry.Headers)
|
|
{
|
|
writer.Write(header.Key);
|
|
writer.Write(header.Value);
|
|
}
|
|
|
|
writer.Write(entry.Body.Length);
|
|
writer.Write(entry.Body);
|
|
}
|
|
|
|
// See serialization format above
|
|
private static void WriteCachedVaryBy(BinaryWriter writer, CachedVaryBy entry)
|
|
{
|
|
writer.Write('V');
|
|
|
|
writer.Write(entry.Headers.Count);
|
|
foreach (var header in entry.Headers)
|
|
{
|
|
writer.Write(header);
|
|
}
|
|
|
|
writer.Write(entry.Params.Count);
|
|
foreach (var param in entry.Params)
|
|
{
|
|
writer.Write(param);
|
|
}
|
|
}
|
|
}
|
|
}
|