-
Notifications
You must be signed in to change notification settings - Fork 5.5k
Expand file tree
/
Copy pathHttpRequestMessage.cs
More file actions
247 lines (202 loc) · 8.57 KB
/
Copy pathHttpRequestMessage.cs
File metadata and controls
247 lines (202 loc) · 8.57 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
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
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
// 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 PropagatorStateInjectedByDiagnosticsHandler = 2;
private const int MessageDisposed = 4;
private const int AuthDisabled = 8;
// 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
{
if ((uint)value > (uint)HttpVersionPolicy.RequestVersionExact)
{
throw new ArgumentException(SR.Format(SR.net_invalid_enum, nameof(HttpVersionPolicy)), nameof(value));
}
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();
/// <summary>
/// Gets or sets the identifier of the connection that this request was most recently sent on, or <see langword="null"/>
/// if it has not been sent over a <see cref="SocketsHttpHandler"/> connection.
/// </summary>
/// <remarks>
/// The value matches the connection id reported through EventSource telemetry, and the id surfaced to
/// <see cref="SocketsHttpHandler.ConnectCallback"/> and <see cref="SocketsHttpHandler.ShouldEvictConnection"/>,
/// allowing a caller to correlate a request with the connection that served it. When a request is sent over
/// multiple connections (for example after a redirect or a retry), the value reflects the most recent attempt.
/// <para>
/// This property is intended to be read after the request has been sent. Assigning a value before the request
/// is sent has no effect on how the request is handled: it does not request or influence the use of a particular
/// connection, and any value set by the caller is overwritten with the id of the connection that actually serves
/// the request.
/// </para>
/// </remarks>
[Experimental(Experimentals.SocketsHttpHandlerExperimentalDiagId, UrlFormat = Experimentals.SharedUrlFormat)]
public long? ConnectionId { get; set; }
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()
{
ValueStringBuilder sb = new ValueStringBuilder(stackalloc char[512]);
sb.Append("Method: ");
sb.Append(_method.ToString());
sb.Append(", RequestUri: '");
if (_requestUri is null)
{
sb.Append("<null>");
}
else
{
sb.AppendSpanFormattable(_requestUri);
}
sb.Append("', Version: ");
sb.AppendSpanFormattable(_version);
sb.Append(", Content: ");
sb.Append(_content == null ? "<null>" : _content.GetType().ToString());
sb.Append(", Headers:");
sb.Append(Environment.NewLine);
HeaderUtilities.DumpHeaders(ref 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 MarkPropagatorStateInjectedByDiagnosticsHandler() => _sendStatus |= PropagatorStateInjectedByDiagnosticsHandler;
internal bool WasPropagatorStateInjectedByDiagnosticsHandler() => (_sendStatus & PropagatorStateInjectedByDiagnosticsHandler) != 0;
internal void DisableAuth() => _sendStatus |= AuthDisabled;
internal bool IsAuthDisabled() => (_sendStatus & AuthDisabled) != 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);
}
}
}