public static void AddDefaultRequestHeaders(HttpClient httpClient) { // The Schema version is 3.1, put into the Microsoft-BotFramework header var botFwkProductInfo = new ProductInfoHeaderValue("Microsoft-BotFramework", "3.1"); if (!httpClient.DefaultRequestHeaders.UserAgent.Contains(botFwkProductInfo)) { httpClient.DefaultRequestHeaders.UserAgent.Add(botFwkProductInfo); } // The Client SDK Version // https://github.com/Microsoft/botbuilder-dotnet/blob/d342cd66d159a023ac435aec0fdf791f93118f5f/doc/UserAgents.md var botBuilderProductInfo = new ProductInfoHeaderValue("BotBuilder", GetClientVersion()); if (!httpClient.DefaultRequestHeaders.UserAgent.Contains(botBuilderProductInfo)) { httpClient.DefaultRequestHeaders.UserAgent.Add(botBuilderProductInfo); } // Additional Info. // https://github.com/Microsoft/botbuilder-dotnet/blob/d342cd66d159a023ac435aec0fdf791f93118f5f/doc/UserAgents.md var userAgent = $"({GetASPNetVersion()}; {GetOsVersion()}; {GetArchitecture()})"; if (ProductInfoHeaderValue.TryParse(userAgent, out var additionalProductInfo)) { if (!httpClient.DefaultRequestHeaders.UserAgent.Contains(additionalProductInfo)) { httpClient.DefaultRequestHeaders.UserAgent.Add(additionalProductInfo); } } httpClient.DefaultRequestHeaders.ExpectContinue = false; }
private void CheckInvalidTryParse(string input) { ProductInfoHeaderValue result = null; Assert.False(ProductInfoHeaderValue.TryParse(input, out result)); Assert.Null(result); }
public static HttpRequestMessage UserAgent(this HttpRequestMessage request, string agent) { if (request is null) { throw new ArgumentNullException(nameof(request)); } var parts = agent.Split(' ').ToList(); for (var i = parts.Count - 1; i > 0; i--) { if (parts[i].EndsWith(')') && !parts[i].StartsWith('(')) { parts[i - 1] += " " + parts[i]; parts.RemoveAt(i); } } request.Headers.UserAgent.Clear(); foreach (var part in parts) { if (ProductInfoHeaderValue.TryParse(part, out var value)) { request.Headers.UserAgent.Add(value); } } return(request); }
private void CheckValidTryParse(string input, ProductInfoHeaderValue expectedResult) { ProductInfoHeaderValue result = null; Assert.True(ProductInfoHeaderValue.TryParse(input, out result)); Assert.Equal(expectedResult, result); }
private void CheckInvalidParse(string input) { Assert.Throws <FormatException>(() => { ProductInfoHeaderValue.Parse(input); }); Assert.False(ProductInfoHeaderValue.TryParse(input, out ProductInfoHeaderValue result)); Assert.Null(result); }
partial void CustomInitialize() { // The Schema version is 3.1, put into the Microsoft-BotFramework header // https://github.com/Microsoft/botbuilder-dotnet/issues/471 HttpClient.DefaultRequestHeaders.UserAgent.Add(new ProductInfoHeaderValue("Microsoft-BotFramework", "3.1")); // The Client SDK Version // https://github.com/Microsoft/botbuilder-dotnet/blob/d342cd66d159a023ac435aec0fdf791f93118f5f/doc/UserAgents.md HttpClient.DefaultRequestHeaders.UserAgent.Add(new ProductInfoHeaderValue("BotBuilder", GetClientVersion(this))); // Additional Info. Conditionally add this to avoid any illegal characters in the ProductInfo. // https://github.com/Microsoft/botbuilder-dotnet/blob/d342cd66d159a023ac435aec0fdf791f93118f5f/doc/UserAgents.md var platformUserAgent = $"({GetASPNetVersion()}; {GetOsVersion()}; {GetArchitecture()})"; if (ProductInfoHeaderValue.TryParse(platformUserAgent, out var item)) { HttpClient.DefaultRequestHeaders.UserAgent.Add(item); } HttpClient.DefaultRequestHeaders.ExpectContinue = false; // Override the contract resolver with the Default because we want to be able to serialize annonymous types SerializationSettings.ContractResolver = new DefaultContractResolver(); DeserializationSettings.ContractResolver = new DefaultContractResolver(); }
public void TryParse_Invalid() { ProductInfoHeaderValue res; Assert.IsFalse(ProductInfoHeaderValue.TryParse("", out res), "#1"); Assert.IsNull(res, "#2"); }
/// <summary> /// Returns <c>true</c> if the User-Agent HTTP header value is valid, otherwise returns <c>false</c>. /// </summary> /// <param name="headerValues">The header values.</param> /// <returns><c>true</c> if the User-Agent HTTP header values are valid; otherwise, <c>false</c>.</returns> public override bool IsValid(StringValues headerValues) { var isValid = false; if (!StringValues.IsNullOrEmpty(headerValues)) { var value = string.Join(" ", headerValues); var values = Split(value) .Select( x => { var parsed = ProductInfoHeaderValue.TryParse(x, out ProductInfoHeaderValue productInfo); return(new { Parsed = parsed, ProductInfo = productInfo }); }) .ToArray(); isValid = values.All(x => x.Parsed) && values .Where(x => x.ProductInfo.Product != null) .All(x => !string.IsNullOrWhiteSpace(x.ProductInfo.Product.Name)); } return(isValid); }
public void TryParse() { ProductInfoHeaderValue res; Assert.IsTrue(ProductInfoHeaderValue.TryParse("a", out res), "#1"); Assert.AreEqual("a", res.Product.Name, "#2"); Assert.IsNull(res.Comment, "#3"); }
public static bool TryGetUserAgent(this IHttpRequest req, out ProductInfoHeaderValue userAgent) { if (!req.TryGetHeader(HeaderKeyUserAgent, out string userAgentString)) { userAgent = default; return(false); } return(ProductInfoHeaderValue.TryParse(userAgentString, out userAgent)); }
static WebWrapper() { ServicePointManager.DefaultConnectionLimit = int.MaxValue; httpClient.Timeout = DefaultTimeout; httpClient.DefaultRequestHeaders.UserAgent.Clear(); ProductInfoHeaderValue version = ProductInfoHeaderValue.TryParse($"TS3AudioBot/{Environment.SystemData.AssemblyData.Version}", out var v) ? v : new ProductInfoHeaderValue("TS3AudioBot", "1.3.3.7"); httpClient.DefaultRequestHeaders.UserAgent.Add(version); }
private bool SetUserAgent(string userAgent) { if (ProductInfoHeaderValue.TryParse(userAgent, out var additionalProductInfo)) { if (!HttpClient.DefaultRequestHeaders.UserAgent.Contains(additionalProductInfo)) { HttpClient.DefaultRequestHeaders.UserAgent.Add(additionalProductInfo); return(true); } } return(false); }
/// <summary> /// Creates a new System.Net.Http.HttpClient instance configured with the Graph.Community middleware plus the handlers provided. /// </summary> /// <param name="options">The <see cref="CommunityGraphClientOptions"/> to use.</param> /// <param name="handlers">An ordered list of System.Net.Http.DelegatingHandler instances to be invoked</param> /// <param name="version">The graph version to use.</param> /// <param name="nationalCloud">The national cloud endpoint to use.</param> /// <param name="proxy">The proxy to be used with created client.</param> /// <param name="finalHandler">The last HttpMessageHandler to HTTP calls.</param> /// <returns>A GraphServiceClient instance with the configured handlers.</returns> public static GraphServiceClient Create(CommunityGraphClientOptions options, IList <DelegatingHandler> handlers, string version = "v1.0", string nationalCloud = "Global", IWebProxy proxy = null, HttpMessageHandler finalHandler = null) { if (options == null) { throw new ArgumentNullException("options"); } ProductInfoHeaderValue defaultUserAgent = defaultDecoration.ToUserAgent(); ProductInfoHeaderValue specifiedUserAgent = default; if (!options.UserAgentInfo.IsEmpty()) { specifiedUserAgent = options.UserAgentInfo.ToUserAgent(); } else { // if we got a user agent string, validate it if (!string.IsNullOrEmpty(options.UserAgent)) { if (!ProductInfoHeaderValue.TryParse(options.UserAgent, out specifiedUserAgent)) { throw new ArgumentOutOfRangeException("CommunityGraphClientOptions.UserAgent", "Cannot parse UserAgent string"); } } } handlers.Insert(0, new SharePointServiceHandler()); var httpClient = GraphClientFactory.Create(handlers, version, nationalCloud, proxy, finalHandler); if (specifiedUserAgent != null) { httpClient.DefaultRequestHeaders.UserAgent.Add(specifiedUserAgent); } // if the provided string does not have the SharePoint throttling decoration, add the library user agent to the default. // https://docs.microsoft.com/en-us/sharepoint/dev/general-development/how-to-avoid-getting-throttled-or-blocked-in-sharepoint-online#how-to-decorate-your-http-traffic-to-avoid-throttling if (!specifiedUserAgent.ToString().Contains("ISV")) { httpClient.DefaultRequestHeaders.UserAgent.Add(defaultUserAgent); } httpClient.DefaultRequestHeaders.Add(CommunityGraphConstants.Library.VersionHeaderName, CommunityGraphConstants.Library.VersionHeaderValue); var graphServiceClient = new GraphServiceClient(httpClient); return(graphServiceClient); }
public static HttpClient CreateClient(Uri baseUri, HttpMessageHandler handler, bool disposeHandler, DynamicRestClientDefaults defaults) { if (handler == null) { throw new ArgumentNullException("handler"); } var client = new HttpClient(handler, disposeHandler); client.BaseAddress = baseUri; #if !WINDOWS_UWP if (handler is HttpClientHandler && ((HttpClientHandler)handler).SupportsTransferEncodingChunked()) { client.DefaultRequestHeaders.TransferEncodingChunked = true; } #endif client.DefaultRequestHeaders.Accept.Clear(); if (defaults == null || !defaults.DefaultHeaders.ContainsKey("Accept")) { client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json")); client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("text/json")); client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("text/x-json")); client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("text/javascript")); } if (defaults != null) { ProductInfoHeaderValue productHeader = null; if (!string.IsNullOrEmpty(defaults.UserAgent) && ProductInfoHeaderValue.TryParse(defaults.UserAgent, out productHeader)) { client.DefaultRequestHeaders.UserAgent.Clear(); client.DefaultRequestHeaders.UserAgent.Add(productHeader); } foreach (var kvp in defaults.DefaultHeaders) { client.DefaultRequestHeaders.Add(kvp.Key, kvp.Value); } if (!string.IsNullOrEmpty(defaults.AuthToken) && !string.IsNullOrEmpty(defaults.AuthScheme)) { client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue(defaults.AuthScheme, defaults.AuthToken); } } return(client); }
public void StreamingRequestHandler_UserAgent_Matches_Standard_Format() { var s = new StreamingRequestHandler(null, new MockBot(), null); var client = new HttpClient(); var userAgentHeader = client.DefaultRequestHeaders.UserAgent; // The Schema version is 3.1, put into the Microsoft-BotFramework header var botFwkProductInfo = new ProductInfoHeaderValue("Microsoft-BotFramework", "3.1"); if (!userAgentHeader.Contains(botFwkProductInfo)) { userAgentHeader.Add(botFwkProductInfo); } // Info on Streaming Extensions Version var streamingExtensionsVersion = new ProductInfoHeaderValue("Streaming-Extensions", "1.0"); if (!userAgentHeader.Contains(streamingExtensionsVersion)) { userAgentHeader.Add(streamingExtensionsVersion); } // The Client SDK Version // https://github.com/Microsoft/botbuilder-dotnet/blob/d342cd66d159a023ac435aec0fdf791f93118f5f/doc/UserAgents.md var botBuilderProductInfo = new ProductInfoHeaderValue("BotBuilder", ConnectorClient.GetClientVersion(new ConnectorClient(new System.Uri("http://localhost")))); if (!userAgentHeader.Contains(botBuilderProductInfo)) { userAgentHeader.Add(botBuilderProductInfo); } // Additional Info. // https://github.com/Microsoft/botbuilder-dotnet/blob/d342cd66d159a023ac435aec0fdf791f93118f5f/doc/UserAgents.md var userAgent = $"({ConnectorClient.GetASPNetVersion()}; {ConnectorClient.GetOsVersion()}; {ConnectorClient.GetArchitecture()})"; if (ProductInfoHeaderValue.TryParse(userAgent, out var additionalProductInfo)) { if (!userAgentHeader.Contains(additionalProductInfo)) { userAgentHeader.Add(additionalProductInfo); } } Assert.AreEqual(s.UserAgent, userAgentHeader.ToString()); }
private HttpClient CreateClient() { var handler = new HttpClientHandler(); if (handler.SupportsAutomaticDecompression) { handler.AutomaticDecompression = DecompressionMethods.GZip | DecompressionMethods.Deflate; } var client = new HttpClient(handler, true); client.BaseAddress = new Uri(_baseUrl, UriKind.Absolute); client.DefaultRequestHeaders.Accept.Clear(); client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json")); client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("text/json")); client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("text/x-json")); client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("text/javascript")); if (handler.SupportsTransferEncodingChunked()) { client.DefaultRequestHeaders.TransferEncodingChunked = true; } if (_defaults != null) { ProductInfoHeaderValue productHeader = null; if (!string.IsNullOrEmpty(_defaults.UserAgent) && ProductInfoHeaderValue.TryParse(_defaults.UserAgent, out productHeader)) { client.DefaultRequestHeaders.UserAgent.Clear(); client.DefaultRequestHeaders.UserAgent.Add(productHeader); } foreach (var kvp in _defaults.DefaultHeaders) { client.DefaultRequestHeaders.Add(kvp.Key, kvp.Value); } if (!string.IsNullOrEmpty(_defaults.AuthToken) && !string.IsNullOrEmpty(_defaults.AuthScheme)) { client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue(_defaults.AuthScheme, _defaults.AuthToken); } } return(client); }
public static HttpClient CreateClient(HttpMessageHandler handler, string user_agent) { var client = new HttpClient(handler, false); client.BaseAddress = new Uri("http://dev.virtualearth.net/REST/v1/", UriKind.Absolute); client.DefaultRequestHeaders.Accept.Clear(); client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json")); ProductInfoHeaderValue productHeader = null; if (!string.IsNullOrEmpty(user_agent) && ProductInfoHeaderValue.TryParse(user_agent, out productHeader)) { client.DefaultRequestHeaders.UserAgent.Clear(); client.DefaultRequestHeaders.UserAgent.Add(productHeader); } return(client); }
public static void ChangeAgent(this HttpClient client, string userAgent, bool overrideAgent = false) { var agent = client?.DefaultRequestHeaders?.UserAgent; bool isValid = ProductInfoHeaderValue.TryParse(userAgent ?? string.Empty, out ProductInfoHeaderValue parsedAgent); if (agent == null || !isValid) { return; } if (!agent.Any()) { agent.Add(parsedAgent); } else if (overrideAgent) { agent.Clear(); agent.Add(parsedAgent); } }
/// <summary> /// Configures an HTTP client to include default headers for the Bot Framework. /// </summary> /// <param name="httpClient">The HTTP client to configure.</param> public static void AddDefaultRequestHeaders(HttpClient httpClient) { lock (httpClient) { // The Schema version is 3.1, put into the Microsoft-BotFramework header var botFwkProductInfo = new ProductInfoHeaderValue("Microsoft-BotFramework", "3.1"); if (!httpClient.DefaultRequestHeaders.UserAgent.Contains(botFwkProductInfo)) { httpClient.DefaultRequestHeaders.UserAgent.Add(botFwkProductInfo); } // The Client SDK Version // https://github.com/Microsoft/botbuilder-dotnet/blob/d342cd66d159a023ac435aec0fdf791f93118f5f/doc/UserAgents.md var botBuilderProductInfo = new ProductInfoHeaderValue("BotBuilder", GetClientVersion()); if (!httpClient.DefaultRequestHeaders.UserAgent.Contains(botBuilderProductInfo)) { httpClient.DefaultRequestHeaders.UserAgent.Add(botBuilderProductInfo); } // Additional Info. // https://github.com/Microsoft/botbuilder-dotnet/blob/d342cd66d159a023ac435aec0fdf791f93118f5f/doc/UserAgents.md var framework = GetASPNetVersion(); if (!string.IsNullOrWhiteSpace(framework) && framework.Length > 0) { // from: // .NETCoreApp,Version=v3.1 // to: // .NETCoreAppVersion/v3.1 // from: // .NET Framework 4.8.4250.0 // to: // .NETFramework/4.8.4250.0 var splitFramework = framework.Replace(",", string.Empty).Replace(" ", string.Empty).Split('='); if (splitFramework.Length > 1) { ProductInfoHeaderValue aspProductInfo = null; if (ProductInfoHeaderValue.TryParse($"{splitFramework[0]}/{splitFramework[1]}", out aspProductInfo)) { if (!httpClient.DefaultRequestHeaders.UserAgent.Contains(aspProductInfo)) { httpClient.DefaultRequestHeaders.UserAgent.Add(aspProductInfo); } } } else if (splitFramework.Length > 0) { framework = splitFramework[0]; // Parse the version from the framework string. Regex regEx = new Regex(@"(?:(\d+)\.)?(?:(\d+)\.)?(?:(\d+)\.\d+)", RegexOptions.Compiled); var version = regEx.Match(framework); if (version.Success) { framework = framework.Replace(version.Value, string.Empty).Trim(); ProductInfoHeaderValue aspProductInfo = null; if (ProductInfoHeaderValue.TryParse($"{framework}/{version.Value}", out aspProductInfo)) { if (!httpClient.DefaultRequestHeaders.UserAgent.Contains(aspProductInfo)) { httpClient.DefaultRequestHeaders.UserAgent.Add(aspProductInfo); } } } } } httpClient.DefaultRequestHeaders.ExpectContinue = false; var jsonAcceptHeader = new MediaTypeWithQualityHeaderValue("*/*"); if (!httpClient.DefaultRequestHeaders.Accept.Contains(jsonAcceptHeader)) { httpClient.DefaultRequestHeaders.Accept.Add(jsonAcceptHeader); } } }
/// <summary> /// Construct and validates <see cref="ApiHeaders"/> from a set of <paramref name="requestHeaders"/> /// </summary> /// <param name="requestHeaders">The <see cref="RequestHeaders"/> containing the <see cref="ApiHeaders"/></param> public ApiHeaders(RequestHeaders requestHeaders) { if (requestHeaders == null) { throw new ArgumentNullException(nameof(requestHeaders)); } var jsonAccept = new Microsoft.Net.Http.Headers.MediaTypeHeaderValue(ApplicationJson); if (!requestHeaders.Accept.Any(x => x.MediaType == jsonAccept.MediaType)) { throw new InvalidOperationException(String.Format(CultureInfo.InvariantCulture, "Client does not accept {0}!", ApplicationJson)); } if (!requestHeaders.Headers.TryGetValue(HeaderNames.UserAgent, out var userAgentValues) || userAgentValues.Count == 0) { throw new InvalidOperationException(String.Format(CultureInfo.InvariantCulture, "Missing {0} headers!", HeaderNames.UserAgent)); } RawUserAgent = userAgentValues.First(); if (String.IsNullOrWhiteSpace(RawUserAgent)) { throw new InvalidOperationException("Malformed client User-Agent!"); } // make sure the api header matches ours if (!requestHeaders.Headers.TryGetValue(ApiVersionHeader, out var apiUserAgentHeaderValues) || !ProductInfoHeaderValue.TryParse(apiUserAgentHeaderValues.FirstOrDefault(), out var apiUserAgent) || apiUserAgent.Product.Name != AssemblyName.Name) { throw new InvalidOperationException("Missing API version!"); } if (!Version.TryParse(apiUserAgent.Product.Version, out var apiVersion)) { throw new InvalidOperationException("Malformed API version!"); } ApiVersion = apiVersion.Semver(); if (!requestHeaders.Headers.TryGetValue(HeaderNames.Authorization, out StringValues authorization)) { throw new InvalidOperationException(String.Format(CultureInfo.InvariantCulture, "Missing {0} header!", HeaderNames.Authorization)); } var auth = authorization.First(); var splits = new List <string>(auth.Split(' ')); var scheme = splits.First(); if (String.IsNullOrWhiteSpace(scheme)) { throw new InvalidOperationException("Missing authentication scheme!"); } splits.RemoveAt(0); var parameter = String.Concat(splits); if (String.IsNullOrEmpty(parameter)) { throw new InvalidOperationException("Missing authentication parameter!"); } if (requestHeaders.Headers.TryGetValue(InstanceIdHeader, out var instanceIdValues)) { var instanceIdString = instanceIdValues.FirstOrDefault(); if (instanceIdString != default && Int64.TryParse(instanceIdString, out var instanceId)) { InstanceId = instanceId; } } #pragma warning disable CA1308 // Normalize strings to uppercase switch (scheme.ToLowerInvariant()) #pragma warning restore CA1308 // Normalize strings to uppercase { case JwtAuthenticationScheme: Token = parameter; break; case PasswordAuthenticationScheme: Password = parameter; var fail = !requestHeaders.Headers.TryGetValue(UsernameHeader, out var values); if (!fail) { Username = values.FirstOrDefault(); fail = String.IsNullOrWhiteSpace(Username); } if (fail) { throw new InvalidOperationException("Missing Username header!"); } break; case BasicAuthenticationScheme: string joinedString; try { var base64Bytes = Convert.FromBase64String(parameter); joinedString = Encoding.UTF8.GetString(base64Bytes); } catch { throw new InvalidOperationException("Invalid basic Authorization header!"); } var basicAuthSplits = joinedString.Split(new char[] { ':' }, StringSplitOptions.RemoveEmptyEntries); if (basicAuthSplits.Length < 2) { throw new InvalidOperationException("Invalid basic Authorization header!"); } Username = basicAuthSplits.First(); Password = String.Concat(basicAuthSplits.Skip(1)); break; default: throw new InvalidOperationException("Invalid authentication scheme!"); } }
/// <summary> /// Initializes a new instance of the <see cref="ApiHeaders"/> class. /// </summary> /// <param name="requestHeaders">The <see cref="RequestHeaders"/> containing the serialized <see cref="ApiHeaders"/>.</param> /// <param name="ignoreMissingAuth">If a missing <see cref="HeaderNames.Authorization"/> should be ignored.</param> /// <exception cref="HeadersException">Thrown if the <paramref name="requestHeaders"/> constitue invalid <see cref="ApiHeaders"/>.</exception> #pragma warning disable CA1502 public ApiHeaders(RequestHeaders requestHeaders, bool ignoreMissingAuth = false) { if (requestHeaders == null) { throw new ArgumentNullException(nameof(requestHeaders)); } var badHeaders = HeaderTypes.None; var errorBuilder = new StringBuilder(); void AddError(HeaderTypes headerType, string message) { if (badHeaders != HeaderTypes.None) { errorBuilder.AppendLine(); } badHeaders |= headerType; errorBuilder.Append(message); } var jsonAccept = new Microsoft.Net.Http.Headers.MediaTypeHeaderValue(MediaTypeNames.Application.Json); if (!requestHeaders.Accept.Any(x => jsonAccept.IsSubsetOf(x))) { AddError(HeaderTypes.Accept, $"Client does not accept {MediaTypeNames.Application.Json}!"); } if (!requestHeaders.Headers.TryGetValue(HeaderNames.UserAgent, out var userAgentValues) || userAgentValues.Count == 0) { AddError(HeaderTypes.UserAgent, $"Missing {HeaderNames.UserAgent} header!"); } else { RawUserAgent = userAgentValues.First(); if (String.IsNullOrWhiteSpace(RawUserAgent)) { AddError(HeaderTypes.UserAgent, $"Malformed {HeaderNames.UserAgent} header!"); } } // make sure the api header matches ours Version?apiVersion = null; if (!requestHeaders.Headers.TryGetValue(ApiVersionHeader, out var apiUserAgentHeaderValues) || !ProductInfoHeaderValue.TryParse(apiUserAgentHeaderValues.FirstOrDefault(), out var apiUserAgent) || apiUserAgent.Product.Name != AssemblyName.Name) { AddError(HeaderTypes.Api, $"Missing {ApiVersionHeader} header!"); } else if (!Version.TryParse(apiUserAgent.Product.Version, out apiVersion)) { AddError(HeaderTypes.Api, $"Malformed {ApiVersionHeader} header!"); } if (!requestHeaders.Headers.TryGetValue(HeaderNames.Authorization, out StringValues authorization)) { if (!ignoreMissingAuth) { AddError(HeaderTypes.Authorization, $"Missing {HeaderNames.Authorization} header!"); } } else { var auth = authorization.First(); var splits = new List <string>(auth.Split(' ')); var scheme = splits.First(); if (String.IsNullOrWhiteSpace(scheme)) { AddError(HeaderTypes.Authorization, "Missing authentication scheme!"); } else { splits.RemoveAt(0); var parameter = String.Concat(splits); if (String.IsNullOrEmpty(parameter)) { AddError(HeaderTypes.Authorization, "Missing authentication parameter!"); } else { if (requestHeaders.Headers.TryGetValue(InstanceIdHeader, out var instanceIdValues)) { var instanceIdString = instanceIdValues.FirstOrDefault(); if (instanceIdString != default && Int64.TryParse(instanceIdString, out var instanceId)) { InstanceId = instanceId; } } switch (scheme) { case OAuthAuthenticationScheme: if (requestHeaders.Headers.TryGetValue(OAuthProviderHeader, out StringValues oauthProviderValues)) { var oauthProviderString = oauthProviderValues.First(); if (Enum.TryParse <OAuthProvider>(oauthProviderString, out var oauthProvider)) { OAuthProvider = oauthProvider; } else { AddError(HeaderTypes.OAuthProvider, "Invalid OAuth provider!"); } } else { AddError(HeaderTypes.OAuthProvider, $"Missing {OAuthProviderHeader} header!"); } goto case BearerAuthenticationScheme; case BearerAuthenticationScheme: Token = parameter; break; case BasicAuthenticationScheme: string badBasicAuthHeaderMessage = $"Invalid basic {HeaderNames.Authorization} header!"; string joinedString; try { var base64Bytes = Convert.FromBase64String(parameter); joinedString = Encoding.UTF8.GetString(base64Bytes); } catch { AddError(HeaderTypes.Authorization, badBasicAuthHeaderMessage); break; } var basicAuthSplits = joinedString.Split(new char[] { ':' }, StringSplitOptions.RemoveEmptyEntries); if (basicAuthSplits.Length < 2) { AddError(HeaderTypes.Authorization, badBasicAuthHeaderMessage); break; } Username = basicAuthSplits.First(); Password = String.Concat(basicAuthSplits.Skip(1)); break; default: AddError(HeaderTypes.Authorization, "Invalid authentication scheme!"); break; } } } } if (badHeaders != HeaderTypes.None) { throw new HeadersException(badHeaders, errorBuilder.ToString()); } ApiVersion = apiVersion !.Semver(); }
/// <summary> /// Construct and validates <see cref="ApiHeaders"/> from a set of <paramref name="requestHeaders"/> /// </summary> /// <param name="requestHeaders">The <see cref="RequestHeaders"/> containing the <see cref="ApiHeaders"/></param> public ApiHeaders(RequestHeaders requestHeaders) { var jsonAccept = new Microsoft.Net.Http.Headers.MediaTypeHeaderValue(ApplicationJson); if (!requestHeaders.Accept.Any(x => x.MediaType == jsonAccept.MediaType)) { throw new InvalidOperationException(String.Format(CultureInfo.InvariantCulture, "Client does not accept {0}!", ApplicationJson)); } if (!requestHeaders.Headers.TryGetValue(HeaderNames.UserAgent, out var userAgentValues) || !ProductInfoHeaderValue.TryParse(userAgentValues.FirstOrDefault(), out var clientUserAgent)) { throw new InvalidOperationException(String.Format(CultureInfo.InvariantCulture, "Missing {0} headers!", HeaderNames.UserAgent)); } // assure the client user agent has a name and version if (String.IsNullOrWhiteSpace(clientUserAgent.Product.Name) || !Version.TryParse(clientUserAgent.Product.Version, out var clientVersion)) { throw new InvalidOperationException("Malformed client user agent!"); } // make sure the api header matches ours if (!requestHeaders.Headers.TryGetValue(ApiVersionHeader, out var apiUserAgentHeaderValues) || !ProductInfoHeaderValue.TryParse(apiUserAgentHeaderValues.FirstOrDefault(), out var apiUserAgent) || apiUserAgent.Product.Name != AssemblyName.Name) { throw new InvalidOperationException("Missing API version!"); } if (!Version.TryParse(apiUserAgent.Product.Version, out var apiVersion)) { throw new InvalidOperationException("Malformed API version!"); } ApiVersion = apiVersion; UserAgent = clientUserAgent.Product; if (!requestHeaders.Headers.TryGetValue(HeaderNames.Authorization, out StringValues authorization)) { throw new InvalidOperationException(String.Format(CultureInfo.InvariantCulture, "Missing {0} header!", HeaderNames.Authorization)); } var auth = authorization.First(); var splits = new List <string>(auth.Split(' ')); var scheme = splits.First(); if (String.IsNullOrWhiteSpace(scheme)) { throw new InvalidOperationException("Missing authentication scheme!"); } splits.RemoveAt(0); var parameter = String.Concat(splits); if (String.IsNullOrEmpty(parameter)) { throw new InvalidOperationException("Missing authentication parameter!"); } if (requestHeaders.Headers.TryGetValue(InstanceIdHeader, out var instanceIdValues)) { var instanceIdString = instanceIdValues.FirstOrDefault(); if (instanceIdString != default && Int64.TryParse(instanceIdString, out var instanceId)) { InstanceId = instanceId; } } switch (scheme) { case JwtAuthenticationScheme: Token = parameter; break; case PasswordAuthenticationScheme: Password = parameter; var fail = !requestHeaders.Headers.TryGetValue(UsernameHeader, out var values); if (!fail) { Username = values.FirstOrDefault(); fail = String.IsNullOrWhiteSpace(Username); } if (fail) { throw new InvalidOperationException("Missing Username header!"); } break; default: throw new InvalidOperationException("Invalid authentication scheme!"); } }
/// <summary> /// Test to see whether or not the user agent is usable /// </summary> /// <param name="customUserAgent">User Agent string to test</param> /// <returns>True if valid, False if it will throw exceptions when parsed</returns> public static bool CanUseUserAgent(string customUserAgent) { ProductInfoHeaderValue unused = null; return(ProductInfoHeaderValue.TryParse(customUserAgent, out unused)); }