2using System.Collections.Generic;
3using System.Globalization;
5using System.Net.Http.Headers;
7using System.Reflection;
10using Microsoft.AspNetCore.Http.Headers;
11using Microsoft.Extensions.Primitives;
12using Microsoft.Net.Http.Headers;
89 public ProductHeaderValue?
UserAgent => ProductInfoHeaderValue.TryParse(
RawUserAgent, out var userAgent) ? userAgent.Product :
null;
136 public static bool CheckCompatibility(
Version otherVersion) => Version.Major == (otherVersion?.Major ??
throw new ArgumentNullException(nameof(otherVersion)));
144 : this(userAgent, token, null, null)
146 if (userAgent ==
null)
147 throw new ArgumentNullException(nameof(userAgent));
149 throw new ArgumentNullException(nameof(token));
151 throw new InvalidOperationException(
"token.Bearer must be set!");
161 : this(userAgent, null, null, null)
163 if (userAgent ==
null)
164 throw new ArgumentNullException(nameof(userAgent));
166 OAuthCode = oAuthCode ??
throw new ArgumentNullException(nameof(oAuthCode));
176 public ApiHeaders(ProductHeaderValue userAgent,
string username,
string password)
177 : this(userAgent, null, username, password)
179 if (userAgent ==
null)
180 throw new ArgumentNullException(nameof(userAgent));
181 if (username ==
null)
182 throw new ArgumentNullException(nameof(username));
183 if (password ==
null)
184 throw new ArgumentNullException(nameof(password));
194#pragma warning disable CA1502
195 public ApiHeaders(RequestHeaders requestHeaders,
bool ignoreMissingAuth,
bool allowEventStreamAccept)
197 if (requestHeaders ==
null)
198 throw new ArgumentNullException(nameof(requestHeaders));
201 var errorBuilder =
new StringBuilder();
202 var multipleErrors =
false;
207 multipleErrors =
true;
208 errorBuilder.AppendLine();
211 badHeaders |= headerType;
212 errorBuilder.Append(message);
216 var eventStreamAccept =
new Microsoft.Net.Http.Headers.MediaTypeHeaderValue(
TextEventStreamMime);
217 if (!requestHeaders.Accept.Any(jsonAccept.IsSubsetOf))
218 if (!allowEventStreamAccept)
219 AddError(
HeaderErrorTypes.Accept, $
"Client does not accept {ApplicationJsonMime}!");
220 else if (!requestHeaders.Accept.Any(eventStreamAccept.IsSubsetOf))
221 AddError(
HeaderErrorTypes.Accept, $
"Client does not accept {ApplicationJsonMime} or {TextEventStreamMime}!");
223 if (!requestHeaders.Headers.TryGetValue(HeaderNames.UserAgent, out var userAgentValues) || userAgentValues.Count == 0)
224 AddError(
HeaderErrorTypes.UserAgent, $
"Missing {HeaderNames.UserAgent} header!");
229 AddError(
HeaderErrorTypes.UserAgent, $
"Malformed {HeaderNames.UserAgent} header!");
234 if (!requestHeaders.Headers.TryGetValue(
ApiVersionHeader, out var apiUserAgentHeaderValues) || !ProductInfoHeaderValue.TryParse(apiUserAgentHeaderValues.FirstOrDefault(), out var apiUserAgent) || apiUserAgent.Product.Name !=
AssemblyName.Name)
236 else if (!
Version.TryParse(apiUserAgent.Product.Version, out apiVersion))
239 if (!requestHeaders.Headers.TryGetValue(HeaderNames.Authorization, out StringValues authorization))
241 if (!ignoreMissingAuth)
242 AddError(
HeaderErrorTypes.AuthorizationMissing, $
"Missing {HeaderNames.Authorization} header!");
246 var auth = authorization.First();
247 var splits =
new List<string>(auth.Split(
' '));
248 var scheme = splits.First();
249 if (String.IsNullOrWhiteSpace(scheme))
250 AddError(
HeaderErrorTypes.AuthorizationInvalid,
"Missing authentication scheme!");
254 var parameter = String.Concat(splits);
255 if (String.IsNullOrEmpty(parameter))
256 AddError(
HeaderErrorTypes.AuthorizationInvalid,
"Missing authentication parameter!");
259 if (requestHeaders.Headers.TryGetValue(
InstanceIdHeader, out var instanceIdValues))
261 var instanceIdString = instanceIdValues.FirstOrDefault();
262 if (instanceIdString !=
default && Int64.TryParse(instanceIdString, out var instanceId))
269 if (requestHeaders.Headers.TryGetValue(
OAuthProviderHeader, out StringValues oauthProviderValues))
271 var oauthProviderString = oauthProviderValues.First();
272 if (Enum.TryParse<
OAuthProvider>(oauthProviderString, out var oauthProvider))
278 AddError(
HeaderErrorTypes.OAuthProvider, $
"Missing {OAuthProviderHeader} header!");
290#pragma warning disable CS0618
292#pragma warning restore CS0618
294 catch (ArgumentException ex) when (ex is not ArgumentNullException)
296 AddError(
HeaderErrorTypes.AuthorizationInvalid, $
"Invalid JWT: {ex.Message}");
301 string badBasicAuthHeaderMessage = $
"Invalid basic {HeaderNames.Authorization} header!";
305 var base64Bytes = Convert.FromBase64String(parameter);
306 joinedString = Encoding.UTF8.GetString(base64Bytes);
314 var basicAuthSplits = joinedString.Split(
ColonSeparator, StringSplitOptions.RemoveEmptyEntries);
315 if (basicAuthSplits.Length < 2)
322 Password = String.Concat(basicAuthSplits.Skip(1));
325 AddError(
HeaderErrorTypes.AuthorizationInvalid,
"Invalid authentication scheme!");
335 errorBuilder.Insert(0, $
"Multiple header validation errors occurred:{Environment.NewLine}");
342#pragma warning restore CA1502
374 throw new ArgumentNullException(nameof(headers));
376 throw new InvalidOperationException(
"Specified different instance IDs in constructor and SetRequestHeaders!");
380 headers.UserAgent.Add(
new ProductInfoHeaderValue(
UserAgent));
388 headers.Authorization =
new AuthenticationHeaderValue(
390 Convert.ToBase64String(Encoding.UTF8.GetBytes($
"{Username}:{Password}")));
395 if (instanceId.HasValue)
396 headers.Add(
InstanceIdHeader, instanceId.Value.ToString(CultureInfo.InvariantCulture));
406 throw new ArgumentNullException(nameof(headers));
408 headers.Add(HeaderNames.UserAgent,
RawUserAgent ??
throw new InvalidOperationException(
"Missing UserAgent!"));
Represents a JWT returned by the API.
string? Bearer
The value of the JWT.
JsonWebToken ParseJwt()
Parses the Bearer as a JsonWebToken.
Attribute for bringing in the HTTP API version from MSBuild.
static ApiVersionAttribute Instance
Return the Assembly's instance of the ApiVersionAttribute.
string RawApiVersion
The Version string of the TGS API definition.
OAuthProvider
List of OAuth providers supported by TGS.
HeaderErrorTypes
Types of individual ApiHeaders errors.