172 lines
4.7 KiB
C#
172 lines
4.7 KiB
C#
|
namespace Uwaa.HTTP;
|
|||
|
|
|||
|
/// <summary>
|
|||
|
/// General purpose implementation of <see cref="IHttpFields"/>.
|
|||
|
/// </summary>
|
|||
|
public class HttpFields
|
|||
|
{
|
|||
|
public MIMEType[]? Accept;
|
|||
|
|
|||
|
public ConnectionType? Connection;
|
|||
|
|
|||
|
public string? Upgrade;
|
|||
|
|
|||
|
public string? UserAgent;
|
|||
|
|
|||
|
public string? Authorization;
|
|||
|
|
|||
|
public string? WebSocketKey;
|
|||
|
|
|||
|
public string? WebSocketAccept;
|
|||
|
|
|||
|
public string? WebSocketProtocol;
|
|||
|
|
|||
|
public string? Location;
|
|||
|
|
|||
|
public int? ContentLength;
|
|||
|
|
|||
|
public MIMEType? ContentType;
|
|||
|
|
|||
|
/// <summary>
|
|||
|
/// Extra fields to include.
|
|||
|
/// </summary>
|
|||
|
public Dictionary<string, string>? Misc;
|
|||
|
|
|||
|
/// <summary>
|
|||
|
/// Sets a field. The string will be parsed for non-string fields like Accept.
|
|||
|
/// </summary>
|
|||
|
public virtual string? this[string key]
|
|||
|
{
|
|||
|
set
|
|||
|
{
|
|||
|
switch (key.ToLowerInvariant())
|
|||
|
{
|
|||
|
case "accept":
|
|||
|
Accept = value == null ? null : HttpHelpers.ParseAccept(value);
|
|||
|
return;
|
|||
|
|
|||
|
case "connection":
|
|||
|
{
|
|||
|
if (Enum.TryParse(value, true, out ConnectionType conType))
|
|||
|
Connection = conType;
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
case "upgrade":
|
|||
|
Upgrade = value;
|
|||
|
return;
|
|||
|
|
|||
|
case "user-agent":
|
|||
|
UserAgent = value;
|
|||
|
return;
|
|||
|
|
|||
|
case "authorization":
|
|||
|
Authorization = value;
|
|||
|
return;
|
|||
|
|
|||
|
case "sec-websocket-key":
|
|||
|
WebSocketKey = value;
|
|||
|
return;
|
|||
|
|
|||
|
case "sec-websocket-accept":
|
|||
|
WebSocketAccept = value;
|
|||
|
return;
|
|||
|
|
|||
|
case "sec-websocket-protocol":
|
|||
|
WebSocketProtocol = value;
|
|||
|
return;
|
|||
|
|
|||
|
case "location":
|
|||
|
Location = value;
|
|||
|
return;
|
|||
|
|
|||
|
case "content-length":
|
|||
|
{
|
|||
|
if (value == null)
|
|||
|
{
|
|||
|
ContentLength = 0;
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
if (!int.TryParse(value, out int contentLength))
|
|||
|
throw new HttpException("Invalid Content-Length");
|
|||
|
ContentLength = contentLength;
|
|||
|
}
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
case "content-type":
|
|||
|
ContentType = value == null ? (MIMEType?)null: new MIMEType(value);
|
|||
|
return;
|
|||
|
|
|||
|
default:
|
|||
|
if (value == null)
|
|||
|
{
|
|||
|
Misc?.Remove(key);
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
Misc ??= new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
|
|||
|
Misc[key] = value;
|
|||
|
}
|
|||
|
return;
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
/// <summary>
|
|||
|
/// Generates strings for the fields and sends them to the provided callback.
|
|||
|
/// </summary>
|
|||
|
public virtual void EmitAll(FieldCallback callback)
|
|||
|
{
|
|||
|
if (ContentLength.HasValue)
|
|||
|
callback("Content-Length", ContentLength.Value.ToString());
|
|||
|
|
|||
|
if (ContentType.HasValue)
|
|||
|
callback("Content-Type", ContentType.Value.ToString());
|
|||
|
|
|||
|
if (Accept != null)
|
|||
|
callback("Accept", string.Join(", ", Accept));
|
|||
|
|
|||
|
if (Connection.HasValue)
|
|||
|
callback("Connection", Connection.Value switch
|
|||
|
{
|
|||
|
ConnectionType.Close => "close",
|
|||
|
ConnectionType.KeepAlive => "keepalive",
|
|||
|
ConnectionType.Upgrade => "upgrade",
|
|||
|
_ => "close",
|
|||
|
});
|
|||
|
|
|||
|
if (UserAgent != null)
|
|||
|
callback("User-Agent", UserAgent);
|
|||
|
|
|||
|
if (Authorization != null)
|
|||
|
callback("Authorization", Authorization);
|
|||
|
|
|||
|
if (Upgrade != null)
|
|||
|
callback("Upgrade", Upgrade);
|
|||
|
|
|||
|
if (Location != null)
|
|||
|
callback("Location", Location);
|
|||
|
|
|||
|
if (WebSocketKey != null)
|
|||
|
callback("Sec-WebSocket-Key", WebSocketKey);
|
|||
|
|
|||
|
if (WebSocketAccept != null)
|
|||
|
callback("Sec-WebSocket-Accept", WebSocketAccept);
|
|||
|
|
|||
|
if (WebSocketProtocol != null)
|
|||
|
callback("Sec-WebSocket-Protocol", WebSocketProtocol);
|
|||
|
|
|||
|
if (Misc != null)
|
|||
|
foreach (var pair in Misc)
|
|||
|
callback(pair.Key, pair.Value);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
public enum ConnectionType
|
|||
|
{
|
|||
|
Close,
|
|||
|
KeepAlive,
|
|||
|
Upgrade,
|
|||
|
}
|