/
HttpRequestMessage.cs
217 lines (176 loc) · 6.57 KB
/
HttpRequestMessage.cs
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
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
using System.Collections.Generic;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.Net.Http.Headers;
using System.Text;
using System.Threading;
namespace System.Net.Http
{
public class HttpRequestMessage : IDisposable
{
internal static Version DefaultRequestVersion => HttpVersion.Version11;
internal static HttpVersionPolicy DefaultVersionPolicy => HttpVersionPolicy.RequestVersionOrLower;
private const int MessageNotYetSent = 0;
private const int MessageAlreadySent = 1;
private const int MessageIsRedirect = 2;
private const int MessageDisposed = 4;
// Track whether the message has been sent.
// The message shouldn't be sent again if this field is equal to MessageAlreadySent.
private int _sendStatus = MessageNotYetSent;
private HttpMethod _method;
private Uri? _requestUri;
private HttpRequestHeaders? _headers;
private Version _version;
private HttpVersionPolicy _versionPolicy;
private HttpContent? _content;
internal HttpRequestOptions? _options;
public Version Version
{
get { return _version; }
set
{
ArgumentNullException.ThrowIfNull(value);
CheckDisposed();
_version = value;
}
}
/// <summary>
/// Gets or sets the policy determining how <see cref="Version" /> is interpreted and how is the final HTTP version negotiated with the server.
/// </summary>
public HttpVersionPolicy VersionPolicy
{
get { return _versionPolicy; }
set
{
CheckDisposed();
_versionPolicy = value;
}
}
public HttpContent? Content
{
get { return _content; }
set
{
CheckDisposed();
if (NetEventSource.Log.IsEnabled())
{
if (value == null)
{
NetEventSource.ContentNull(this);
}
else
{
NetEventSource.Associate(this, value);
}
}
// It's OK to set a 'null' content, even if the method is POST/PUT.
_content = value;
}
}
public HttpMethod Method
{
get { return _method; }
set
{
ArgumentNullException.ThrowIfNull(value);
CheckDisposed();
_method = value;
}
}
public Uri? RequestUri
{
get { return _requestUri; }
set
{
CheckDisposed();
_requestUri = value;
}
}
public HttpRequestHeaders Headers => _headers ??= new HttpRequestHeaders();
internal bool HasHeaders => _headers != null;
[Obsolete("HttpRequestMessage.Properties has been deprecated. Use Options instead.")]
public IDictionary<string, object?> Properties => Options;
/// <summary>
/// Gets the collection of options to configure the HTTP request.
/// </summary>
public HttpRequestOptions Options => _options ??= new HttpRequestOptions();
public HttpRequestMessage()
: this(HttpMethod.Get, (Uri?)null)
{
}
public HttpRequestMessage(HttpMethod method, Uri? requestUri)
{
ArgumentNullException.ThrowIfNull(method);
// It's OK to have a 'null' request Uri. If HttpClient is used, the 'BaseAddress' will be added.
// If there is no 'BaseAddress', sending this request message will throw.
// Note that we also allow the string to be empty: null and empty are considered equivalent.
_method = method;
_requestUri = requestUri;
_version = DefaultRequestVersion;
_versionPolicy = DefaultVersionPolicy;
}
public HttpRequestMessage(HttpMethod method, [StringSyntax(StringSyntaxAttribute.Uri)] string? requestUri)
: this(method, string.IsNullOrEmpty(requestUri) ? null : new Uri(requestUri, UriKind.RelativeOrAbsolute))
{
}
public override string ToString()
{
StringBuilder sb = new StringBuilder();
sb.Append("Method: ");
sb.Append(_method);
sb.Append(", RequestUri: '");
if (_requestUri is null)
{
sb.Append("<null>");
}
else
{
sb.Append($"{_requestUri}");
}
sb.Append("', Version: ");
sb.Append(_version);
sb.Append(", Content: ");
sb.Append(_content == null ? "<null>" : _content.GetType().ToString());
sb.AppendLine(", Headers:");
HeaderUtilities.DumpHeaders(sb, _headers, _content?.Headers);
return sb.ToString();
}
internal bool MarkAsSent() => Interlocked.CompareExchange(ref _sendStatus, MessageAlreadySent, MessageNotYetSent) == MessageNotYetSent;
internal bool WasSentByHttpClient() => (_sendStatus & MessageAlreadySent) != 0;
internal void MarkAsRedirected() => _sendStatus |= MessageIsRedirect;
internal bool WasRedirected() => (_sendStatus & MessageIsRedirect) != 0;
private bool Disposed
{
get => (_sendStatus & MessageDisposed) != 0;
set
{
Debug.Assert(value);
_sendStatus |= MessageDisposed;
}
}
internal bool IsExtendedConnectRequest => Method == HttpMethod.Connect && _headers?.Protocol != null;
#region IDisposable Members
protected virtual void Dispose(bool disposing)
{
// The reason for this type to implement IDisposable is that it contains instances of types that implement
// IDisposable (content).
if (disposing && !Disposed)
{
Disposed = true;
_content?.Dispose();
}
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
#endregion
private void CheckDisposed()
{
ObjectDisposedException.ThrowIf(Disposed, this);
}
}
}