-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathResponseCookies.cs
More file actions
81 lines (63 loc) · 2.61 KB
/
Copy pathResponseCookies.cs
File metadata and controls
81 lines (63 loc) · 2.61 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
using System.Globalization;
using System.Text;
namespace Shiny.Net.HttpServer;
/// <summary>Options for a Set-Cookie response header.</summary>
public sealed class CookieOptions
{
public string? Domain { get; set; }
public string? Path { get; set; } = "/";
public DateTimeOffset? Expires { get; set; }
public TimeSpan? MaxAge { get; set; }
public bool Secure { get; set; }
public bool HttpOnly { get; set; }
public SameSiteMode SameSite { get; set; } = SameSiteMode.Unspecified;
}
public enum SameSiteMode
{
Unspecified = -1,
None = 0,
Lax = 1,
Strict = 2
}
/// <summary>Appends Set-Cookie headers to a response.</summary>
public sealed class ResponseCookies
{
readonly HttpResponse response;
internal ResponseCookies(HttpResponse response) => this.response = response;
public void Append(string key, string value) => this.Append(key, value, new CookieOptions());
public void Append(string key, string value, CookieOptions options)
{
ArgumentException.ThrowIfNullOrEmpty(key);
ArgumentNullException.ThrowIfNull(options);
var sb = new StringBuilder(64);
sb.Append(key).Append('=').Append(Uri.EscapeDataString(value));
if (!string.IsNullOrEmpty(options.Path))
sb.Append("; path=").Append(options.Path);
if (!string.IsNullOrEmpty(options.Domain))
sb.Append("; domain=").Append(options.Domain);
if (options.Expires is { } expires)
sb.Append("; expires=").Append(expires.ToUniversalTime().ToString("R", CultureInfo.InvariantCulture));
if (options.MaxAge is { } maxAge)
sb.Append("; max-age=").Append(((long)maxAge.TotalSeconds).ToString(CultureInfo.InvariantCulture));
if (options.Secure)
sb.Append("; secure");
if (options.HttpOnly)
sb.Append("; httponly");
switch (options.SameSite)
{
case SameSiteMode.None: sb.Append("; samesite=none"); break;
case SameSiteMode.Lax: sb.Append("; samesite=lax"); break;
case SameSiteMode.Strict: sb.Append("; samesite=strict"); break;
}
this.response.Headers.Append(HeaderNames.SetCookie, sb.ToString());
}
/// <summary>Expires a cookie on the client by setting it to a past date.</summary>
public void Delete(string key) => this.Delete(key, new CookieOptions());
public void Delete(string key, CookieOptions options)
{
ArgumentNullException.ThrowIfNull(options);
options.Expires = DateTimeOffset.UnixEpoch;
options.MaxAge = TimeSpan.Zero;
this.Append(key, string.Empty, options);
}
}