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!");
292 catch (ArgumentException ex) when (ex is not ArgumentNullException)
294 AddError(
HeaderErrorTypes.AuthorizationInvalid, $
"Invalid JWT: {ex.Message}");
299 string badBasicAuthHeaderMessage = $
"Invalid basic {HeaderNames.Authorization} header!";
303 var base64Bytes = Convert.FromBase64String(parameter);
304 joinedString = Encoding.UTF8.GetString(base64Bytes);
312 var basicAuthSplits = joinedString.Split(
ColonSeparator, StringSplitOptions.RemoveEmptyEntries);
313 if (basicAuthSplits.Length < 2)
320 Password = String.Concat(basicAuthSplits.Skip(1));
323 AddError(
HeaderErrorTypes.AuthorizationInvalid,
"Invalid authentication scheme!");
333 errorBuilder.Insert(0, $
"Multiple header validation errors occurred:{Environment.NewLine}");
340#pragma warning restore CA1502
372 throw new ArgumentNullException(nameof(headers));
374 throw new InvalidOperationException(
"Specified different instance IDs in constructor and SetRequestHeaders!");
378 headers.UserAgent.Add(
new ProductInfoHeaderValue(
UserAgent));
386 headers.Authorization =
new AuthenticationHeaderValue(
388 Convert.ToBase64String(Encoding.UTF8.GetBytes($
"{Username}:{Password}")));
393 if (instanceId.HasValue)
394 headers.Add(
InstanceIdHeader, instanceId.Value.ToString(CultureInfo.InvariantCulture));
404 throw new ArgumentNullException(nameof(headers));
406 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.