internal async Task AddAuthHeader(AblyRequest request) { EnsureSecureConnection(); if (request.Headers.ContainsKey("Authorization")) { request.Headers.Remove("Authorization"); } if (AuthMethod == AuthMethod.Basic) { var authInfo = Convert.ToBase64String(Options.Key.GetBytes()); request.Headers["Authorization"] = "Basic " + authInfo; } else { var currentValidToken = await GetCurrentValidTokenAndRenewIfNecessaryAsync(); if (currentValidToken == null) { throw new AblyException("Invalid token credentials: " + CurrentToken, 40100, HttpStatusCode.Unauthorized); } request.Headers["Authorization"] = "Bearer " + CurrentToken.Token.ToBase64(); } }
internal async Task AddAuthHeader(AblyRequest request) { EnsureSecureConnection(); if (request.Headers.ContainsKey("Authorization")) { request.Headers.Remove("Authorization"); } if (AuthMethod == AuthMethod.Basic) { var authInfo = Convert.ToBase64String(Options.Key.GetBytes()); request.Headers["Authorization"] = "Basic " + authInfo; // (RSA7e) If clientId is provided in ClientOptions and RSA4 indicates that basic auth is to be used, then: if (Options.ClientId.IsNotEmpty()) { // (RSA7e2) For REST clients, all requests should include an X-Ably-ClientId header with value set to the clientId, Base64 encoded request.Headers["X-Ably-ClientId"] = Options.ClientId.ToBase64(); } } else { var currentValidToken = await GetCurrentValidTokenAndRenewIfNecessaryAsync(); if (currentValidToken == null) { throw new AblyException("Invalid token credentials: " + CurrentToken, 40100, HttpStatusCode.Unauthorized); } request.Headers["Authorization"] = "Bearer " + CurrentToken.Token.ToBase64(); } }
private async Task <AblyResponse> CallAuthUrl(AuthOptions mergedOptions, TokenParams @params) { var url = mergedOptions.AuthUrl; var protocol = Options.UseBinaryProtocol == false ? Protocol.Json : Protocol.MsgPack; var authRequest = new AblyRequest(url.ToString(), mergedOptions.AuthMethod, protocol); if (mergedOptions.AuthMethod == HttpMethod.Get) { authRequest.AddQueryParameters(@params.ToRequestParams(mergedOptions.AuthParams)); } else { authRequest.PostParameters = @params.ToRequestParams(mergedOptions.AuthParams); } authRequest.Headers = authRequest.Headers.Merge(mergedOptions.AuthHeaders); authRequest.SkipAuthentication = true; AblyResponse response = await _rest.ExecuteRequest(authRequest); if (response.Type == ResponseType.Binary) { throw new AblyException( new ErrorInfo( string.Format("Content Type {0} is not supported by this client library", response.ContentType), 500)); } return(response); }
private HttpRequestMessage GetRequestMessage(AblyRequest request, string host) { var message = new HttpRequestMessage(request.Method, GetRequestUrl(request, host)); foreach (var header in request.Headers) { message.Headers.TryAddWithoutValidation(header.Key, header.Value); } if (request.Protocol == Protocol.MsgPack) { message.Headers.Accept.Add(new MediaTypeWithQualityHeaderValue(GetHeaderValue(request.Protocol))); } //Always accept JSON message.Headers.Accept.Add(new MediaTypeWithQualityHeaderValue(GetHeaderValue(Protocol.Json))); if (message.Method == HttpMethod.Post) { if (request.PostParameters.Any() && request.RequestBody.Length == 0) { message.Content = new FormUrlEncodedContent(request.PostParameters); } else { var content = new ByteArrayContent(request.RequestBody); content.Headers.ContentType = new MediaTypeHeaderValue(GetHeaderValue(request.Protocol)); message.Content = content; } } return(message); }
/// <summary>/// Retrieves the ably service time/// </summary> /// <returns></returns> public async Task <DateTimeOffset> TimeAsync() { AblyRequest request = CreateGetRequest("/time"); request.SkipAuthentication = true; List <long> response = await ExecuteRequest <List <long> >(request); return(response.First().FromUnixTimeInMilliseconds()); }
private string GetQuery(AblyRequest request) { var query = request.QueryParameters.ToQueryString(); if (query.IsNotEmpty()) { return("?" + query); } return(string.Empty); }
internal async Task <AblyResponse> ExecuteRequest(AblyRequest request) { Logger.Debug("Sending {0} request to {1}", request.Method, request.Url); if (request.SkipAuthentication == false) { await AblyAuth.AddAuthHeader(request); } try { MessageHandler.SetRequestBody(request); return(await ExecuteHttpRequest(request)); } catch (AblyException ex) { if (Logger.IsDebug) { Logger.Debug("Error Executing request. Message: " + ex.Message); } if (ex.ErrorInfo.IsUnAuthorizedError && ex.ErrorInfo.IsTokenError && AblyAuth.TokenRenewable) { if (Logger.IsDebug) { Logger.Debug("Handling UnAuthorized Error and repeating request."); } await AblyAuth.AuthoriseAsync(null, new AuthOptions() { Force = true }); await AblyAuth.AddAuthHeader(request); return(await ExecuteHttpRequest(request)); } throw; } catch (Exception ex) { if (Logger.IsDebug) { Logger.Debug("Error Executing request. Message: " + ex.Message); } throw new AblyException(ex); } }
public Uri GetRequestUrl(AblyRequest request, string host = null) { if (host == null) { host = Options.Host; } string protocol = Options.IsSecure ? "https://" : "http://"; if (request.Url.StartsWith("http")) { return(new Uri($"{request.Url}{GetQuery(request)}")); } return(new Uri($"{protocol}{host}{(Options.Port.HasValue ? ":" + Options.Port.Value : string.Empty)}{request.Url}{GetQuery(request)}")); }
internal async Task <PaginatedResult <T> > ExecutePaginatedRequest <T>(AblyRequest request, Func <HistoryRequestParams, Task <PaginatedResult <T> > > executeDataQueryRequest) where T : class { var response = await ExecuteRequest(request); if (Logger.IsDebug) { Logger.Debug("Response received. Status: " + response.StatusCode); Logger.Debug("Content type: " + response.ContentType); Logger.Debug("Encoding: " + response.Encoding); if (response.Body != null) { Logger.Debug("Raw response (base64):" + response.Body.ToBase64()); } } return(MessageHandler.ParsePaginatedResponse <T>(request, response, executeDataQueryRequest)); }
internal async Task <T> ExecuteRequest <T>(AblyRequest request) where T : class { var response = await ExecuteRequest(request); if (Logger.IsDebug) { Logger.Debug("Response received. Status: " + response.StatusCode); Logger.Debug("Content type: " + response.ContentType); Logger.Debug("Encoding: " + response.Encoding); if (response.Body != null) { Logger.Debug("Raw response (base64):" + response.Body.ToBase64()); } } return(MessageHandler.ParseResponse <T>(request, response)); }
public async Task <bool> CanConnectToAbly() { if (Options.SkipInternetCheck) { return(true); } try { var request = new AblyRequest(Defaults.InternetCheckUrl, HttpMethod.Get); var response = await ExecuteHttpRequest(request); return(response.TextResponse == Defaults.InternetCheckOkMessage); } catch (Exception ex) { Logger.Error("Error accessing ably internet check url. Internet is down!", ex); return(false); } }
public Uri GetRequestUrl(AblyRequest request, string host = null) { if (host == null) { host = Options.Host; } string protocol = Options.IsSecure ? "https://" : "http://"; if (request.Url.StartsWith("http")) { return(new Uri(request.Url)); } return(new Uri(string.Format("{0}{1}{2}{3}{4}", protocol, host, Options.Port.HasValue ? ":" + Options.Port.Value : "", request.Url, GetQuery(request)))); }
public async Task <AblyResponse> Execute(AblyRequest request) { var fallbackHosts = Defaults.FallbackHosts.ToList(); if (CustomHost.IsNotEmpty()) { //The custom host is a fallback host currently in use by the Realtime client. //We need to remove it from the fallback hosts fallbackHosts.Remove(CustomHost); } var random = new Random(); int currentTry = 0; var startTime = Config.Now(); var numberOfRetries = Options.HttpMaxRetryCount; var host = CustomHost.IsNotEmpty() ? CustomHost : Options.Host; while (currentTry < numberOfRetries) { var requestTime = Config.Now(); if ((requestTime - startTime).TotalSeconds >= Options.HttpMaxRetryDuration.TotalSeconds) { Logger.Error("Cumulative retry timeout of {0}s was exceeded", Config.CommulativeFailedRequestTimeOutInSeconds); throw new AblyException( new ErrorInfo(string.Format("Commulative retry timeout of {0}s was exceeded.", Config.CommulativeFailedRequestTimeOutInSeconds), 500, null)); } Logger.Debug("Executing request: " + request.Url + (currentTry > 0 ? $"try {currentTry}" : "")); try { var message = GetRequestMessage(request, host); await LogMessage(message); var response = await Client.SendAsync(message, HttpCompletionOption.ResponseContentRead); var ablyResponse = await GetAblyResponse(response); LogResponse(ablyResponse, request.Url); if (response.IsSuccessStatusCode) { return(ablyResponse); } if (IsRetryableResponse(response) && Options.IsDefaultHost) { Logger.Warning("Failed response. Retrying. Returned response with status code: " + response.StatusCode); if (TryGetNextRandomHost(fallbackHosts, random, out host)) { Logger.Debug("Retrying using host {0}", host); currentTry++; continue; } } throw AblyException.FromResponse(ablyResponse); } catch (HttpRequestException ex) when(IsRetryableError(ex) && Options.IsDefaultHost) { Logger.Warning("Error making a connection to Ably servers. Retrying", ex); if (TryGetNextRandomHost(fallbackHosts, random, out host)) { Logger.Debug("Retrying using host {0}", host); currentTry++; continue; } throw; //_host = hosts[currentTry - 1]; } catch (TaskCanceledException ex) when(IsRetryableError(ex) && Options.IsDefaultHost) { Logger.Warning("Error making a connection to Ably servers. Retrying", ex); if (TryGetNextRandomHost(fallbackHosts, random, out host)) { Logger.Debug("Retrying using host {0}", host); currentTry++; continue; } throw; } catch (HttpRequestException ex) { throw new AblyException(new ErrorInfo("Error executing request", 500), ex); } catch (TaskCanceledException ex) { throw new AblyException(new ErrorInfo("Error executing request", 500), ex); } } throw new AblyException(new ErrorInfo("Error exectuting request", 500)); }
public async Task <AblyResponse> Execute(AblyRequest request) { var fallbackHosts = Options.FallbackHosts.ToList(); if (CustomHost.IsNotEmpty()) { // The custom host is a fallback host currently in use by the Realtime client. // We need to remove it from the fallback hosts fallbackHosts.Remove(CustomHost); } var random = new Random(); int currentTry = 0; var startTime = Now(); var numberOfRetries = Options.HttpMaxRetryCount; var host = CustomHost.IsNotEmpty() ? CustomHost : Options.Host; while (currentTry < numberOfRetries) { DateTimeOffset requestTime = Now(); if ((requestTime - startTime).TotalSeconds >= Options.HttpMaxRetryDuration.TotalSeconds) { Logger.Error("Cumulative retry timeout of {0}s was exceeded", Config.CommulativeFailedRequestTimeOutInSeconds); throw new AblyException( new ErrorInfo($"Commulative retry timeout of {Config.CommulativeFailedRequestTimeOutInSeconds}s was exceeded.", 50000, null)); } Logger.Debug("Executing request: " + request.Url + (currentTry > 0 ? $"try {currentTry}" : string.Empty)); try { var message = GetRequestMessage(request, host); await LogMessage(message); var response = await SendAsync(message).ConfigureAwait(false); var ablyResponse = await GetAblyResponse(response); LogResponse(ablyResponse, request.Url); if (response.IsSuccessStatusCode) { return(ablyResponse); } if (IsRetryableResponse(response) && (Options.IsDefaultHost || Options.FallbackHostsUseDefault)) { Logger.Warning("Failed response. Retrying. Returned response with status code: " + response.StatusCode); if (TryGetNextRandomHost(fallbackHosts, random, out host)) { Logger.Debug("Retrying using host {0}", host); currentTry++; continue; } } if (request.NoExceptionOnHttpError) { return(ablyResponse); } try { response.EnsureSuccessStatusCode(); } catch (HttpRequestException ex) { throw new AblyException(ErrorInfo.Parse(ablyResponse), ex); } throw AblyException.FromResponse(ablyResponse); } catch (HttpRequestException ex) when(IsRetryableError(ex) && (Options.IsDefaultHost || Options.FallbackHostsUseDefault)) { Logger.Warning("Error making a connection to Ably servers. Retrying", ex); if (TryGetNextRandomHost(fallbackHosts, random, out host)) { Logger.Debug("Retrying using host {0}", host); currentTry++; continue; } throw; } catch (TaskCanceledException ex) when(IsRetryableError(ex) && (Options.IsDefaultHost || Options.FallbackHostsUseDefault)) { Logger.Warning("Error making a connection to Ably servers. Retrying", ex); if (TryGetNextRandomHost(fallbackHosts, random, out host)) { Logger.Debug("Retrying using host {0}", host); currentTry++; continue; } throw; } catch (HttpRequestException ex) { StringBuilder reason = new StringBuilder(ex.Message); var innerEx = ex.InnerException; while (innerEx != null) { reason.Append(" " + innerEx.Message); innerEx = innerEx.InnerException; } throw new AblyException(new ErrorInfo(reason.ToString(), 50000), ex); } catch (TaskCanceledException ex) { // if the cancellation was not requested then this is timeout. if (ex.CancellationToken.IsCancellationRequested == false) { throw new AblyException(new ErrorInfo("Error executing request. Request timed out.", 50000), ex); } else { throw new AblyException(new ErrorInfo("Error executing request", 50000), ex); } } } throw new AblyException(new ErrorInfo("Error exectuting request", 50000)); }