private async Task <object> InvokeCore(HttpServiceRequest request, Type resultReturnType, JsonSerializerSettings jsonSettings) { if (request == null) { throw new ArgumentNullException(nameof(request)); } request.TracingData = new TracingData { HostName = CurrentApplicationInfo.HostName?.ToUpperInvariant(), ServiceName = AppInfo.Name, RequestID = TracingContext.TryGetRequestID(), SpanID = Guid.NewGuid().ToString("N"), //Each call is new span ParentSpanID = TracingContext.TryGetParentSpanID(), SpanStartTime = DateTimeOffset.UtcNow, AbandonRequestBy = TracingContext.AbandonRequestBy }; PrepareRequest?.Invoke(request); while (true) { var config = GetConfig(); var clientCallEvent = EventPublisher.CreateEvent(); clientCallEvent.TargetService = ServiceName; clientCallEvent.RequestId = request.TracingData?.RequestID; clientCallEvent.TargetMethod = request.Target.MethodName; clientCallEvent.SpanId = request.TracingData?.SpanID; clientCallEvent.ParentSpanId = request.TracingData?.ParentSpanID; string responseContent; HttpResponseMessage response; var nodeAndLoadBalancer = await ServiceDiscovery.GetNode().ConfigureAwait(false); // can throw int?effectivePort = GetEffectivePort(nodeAndLoadBalancer.Node, config); if (effectivePort == null) { throw new ConfigurationException("Cannot access service. Service Port not configured. See tags to find missing configuration", unencrypted: new Tags { { "ServiceName", ServiceName }, { "Required configuration key", $"Discovery.{ServiceName}.DefaultPort" } }); } // The URL is only for a nice experience in Fiddler, it's never parsed/used for anything. var uri = BuildUri(nodeAndLoadBalancer.Node.Hostname, effectivePort.Value, config) + ServiceName; if (request.Target.MethodName != null) { uri += $".{request.Target.MethodName}"; } if (request.Target.Endpoint != null) { uri += $"/{request.Target.Endpoint}"; } try { Log.Debug(_ => _("ServiceProxy: Calling remote service. See tags for details.", unencryptedTags: new { remoteEndpoint = nodeAndLoadBalancer.Node.Hostname, remotePort = effectivePort, remoteServiceName = ServiceName, remoteMethodName = request.Target.MethodName })); clientCallEvent.TargetHostName = nodeAndLoadBalancer.Node.Hostname; clientCallEvent.TargetPort = effectivePort.Value; clientCallEvent.TargetEnvironment = nodeAndLoadBalancer.TargetEnvironment; request.Overrides = TracingContext.TryGetOverrides()?.ShallowCloneWithDifferentPreferredEnvironment(nodeAndLoadBalancer.PreferredEnvironment) ?? new RequestOverrides { PreferredEnvironment = nodeAndLoadBalancer.PreferredEnvironment }; string requestContent = _serializationTime.Time(() => JsonConvert.SerializeObject(request, jsonSettings)); var httpContent = new StringContent(requestContent, Encoding.UTF8, "application/json"); httpContent.Headers.Add(GigyaHttpHeaders.ProtocolVersion, HttpServiceRequest.ProtocolVersion); clientCallEvent.RequestStartTimestamp = Stopwatch.GetTimestamp(); try { response = await GetHttpClient(config).PostAsync(uri, httpContent).ConfigureAwait(false); responseContent = await response.Content.ReadAsStringAsync().ConfigureAwait(false); } finally { clientCallEvent.ResponseEndTimestamp = Stopwatch.GetTimestamp(); } if (response.Headers.TryGetValues(GigyaHttpHeaders.ExecutionTime, out IEnumerable <string> values)) { var time = values.FirstOrDefault(); if (TimeSpan.TryParse(time, out TimeSpan executionTime)) { clientCallEvent.ServerTimeMs = executionTime.TotalMilliseconds; } } } catch (HttpRequestException ex) { Log.Error("The remote service failed to return a valid HTTP response. Continuing to next " + "host. See tags for URL and exception for details.", exception: ex, unencryptedTags: new { uri }); _hostFailureCounter.Increment("RequestFailure"); clientCallEvent.Exception = ex; EventPublisher.TryPublish(clientCallEvent); // fire and forget! if (nodeAndLoadBalancer.LoadBalancer != null) { nodeAndLoadBalancer.LoadBalancer.ReportUnreachable(nodeAndLoadBalancer.Node, ex); continue; } throw; } catch (TaskCanceledException ex) { _failureCounter.Increment("RequestTimeout"); Exception rex = new RemoteServiceException("The request to the remote service exceeded the " + "allotted timeout. See the 'RequestUri' property on this exception for the URL that was " + "called and the tag 'requestTimeout' for the configured timeout.", uri, ex, unencrypted: new Tags { { "requestTimeout", LastHttpClient?.Timeout.ToString() }, { "requestUri", uri } }); clientCallEvent.Exception = rex; EventPublisher.TryPublish(clientCallEvent); // fire and forget! throw rex; } if (response.Headers.Contains(GigyaHttpHeaders.ServerHostname) || response.Headers.Contains(GigyaHttpHeaders.ProtocolVersion)) { try { if (response.IsSuccessStatusCode) { var returnObj = _deserializationTime.Time(() => JsonConvert.DeserializeObject(responseContent, resultReturnType, jsonSettings)); clientCallEvent.ErrCode = 0; EventPublisher.TryPublish(clientCallEvent); // fire and forget! _successCounter.Increment(); return(returnObj); } else { Exception remoteException; try { remoteException = _deserializationTime.Time(() => ExceptionSerializer.Deserialize(responseContent)); } catch (Exception ex) { _applicationExceptionCounter.Increment("ExceptionDeserializationFailure"); throw new RemoteServiceException("The remote service returned a failure response " + "that failed to deserialize. See the 'RequestUri' property on this exception " + "for the URL that was called, the inner exception for the exact error and the " + "'responseContent' encrypted tag for the original response content.", uri, ex, unencrypted: new Tags { { "requestUri", uri } }, encrypted: new Tags { { "responseContent", responseContent } }); } _applicationExceptionCounter.Increment(); clientCallEvent.Exception = remoteException; EventPublisher.TryPublish(clientCallEvent); // fire and forget! if (remoteException is RequestException || remoteException is EnvironmentException) { ExceptionDispatchInfo.Capture(remoteException).Throw(); } if (remoteException is UnhandledException) { remoteException = remoteException.InnerException; } throw new RemoteServiceException("The remote service returned a failure response. See " + "the 'RequestUri' property on this exception for the URL that was called, and the " + "inner exception for details.", uri, remoteException, unencrypted: new Tags { { "requestUri", uri } }); } } catch (JsonException ex) { _failureCounter.Increment("Serialization"); Log.Error("The remote service returned a response with JSON that failed " + "deserialization. See the 'uri' tag for the URL that was called, the exception for the " + "exact error and the 'responseContent' encrypted tag for the original response content.", exception: ex, unencryptedTags: new { uri }, encryptedTags: new { responseContent }); clientCallEvent.Exception = ex; EventPublisher.TryPublish(clientCallEvent); // fire and forget! throw new RemoteServiceException("The remote service returned a response with JSON that " + "failed deserialization. See the 'RequestUri' property on this exception for the URL " + "that was called, the inner exception for the exact error and the 'responseContent' " + "encrypted tag for the original response content.", uri, ex, new Tags { { "responseContent", responseContent } }, new Tags { { "requestUri", uri } }); } } else { var exception = response.StatusCode == HttpStatusCode.ServiceUnavailable ? new Exception($"The remote service is unavailable (503) and is not recognized as a Gigya host at uri: {uri}") : new Exception($"The remote service returned a response but is not recognized as a Gigya host at uri: {uri}"); if (nodeAndLoadBalancer.LoadBalancer == null) { throw exception; } nodeAndLoadBalancer.LoadBalancer.ReportUnreachable(nodeAndLoadBalancer.Node, exception); _hostFailureCounter.Increment("NotGigyaHost"); if (response.StatusCode == HttpStatusCode.ServiceUnavailable) { Log.Error("The remote service is unavailable (503) and is not recognized as a Gigya host. Continuing to next host.", unencryptedTags: new { uri }); } else { Log.Error("The remote service returned a response but is not recognized as a Gigya host. Continuing to next host.", unencryptedTags: new { uri, statusCode = response.StatusCode }, encryptedTags: new { responseContent }); } clientCallEvent.ErrCode = 500001; //(int)GSErrors.General_Server_Error; EventPublisher.TryPublish(clientCallEvent); // fire and forget! } } }
public virtual Task <object> Invoke(HttpServiceRequest request, Type resultReturnType) { return(Invoke(request, resultReturnType, JsonSettings)); }
public virtual async Task <object> Invoke(HttpServiceRequest request, Type resultReturnType, JsonSerializerSettings jsonSettings) { using (_roundtripTime.NewContext()) return(await InvokeCore(request, resultReturnType, jsonSettings).ConfigureAwait(false)); }
private async Task <string> GetResponse(HttpListenerContext context, ServiceMethod serviceMethod, HttpServiceRequest requestData) { var taskType = serviceMethod.ServiceInterfaceMethod.ReturnType; var resultType = taskType.IsGenericType ? taskType.GetGenericArguments().First() : null; var arguments = requestData.Target.IsWeaklyTyped ? GetParametersByName(serviceMethod, requestData.Arguments) : requestData.Arguments.Values.Cast <object>().ToArray(); var settings = requestData.Target.IsWeaklyTyped ? JsonSettingsWeak : JsonSettings; var invocationResult = await Activator.Invoke(serviceMethod, arguments); string response = _serializationTime.Time(() => JsonConvert.SerializeObject(invocationResult.Result, resultType, settings)); context.Response.Headers.Add(GigyaHttpHeaders.ExecutionTime, invocationResult.ExecutionTime.ToString()); return(response); }
private WebApiResponse SendRequest(HttpServiceRequest request) { throw new NotImplementedException(); }
private async Task HandleRequest(HttpListenerContext context, long ticks, long timeFromLastReq) { var sw = _stopwatchPool.Get(); try { var deltaDelayTicks = DateTime.UtcNow.Ticks - ticks; sw.Restart(); RequestTimings.ClearCurrentTimings(); using (context.Response) { // Special endpoints should not be logged/measured/traced like regular endpoints // Access is allowed without HTTPS verifications since they don't expose anything sensitive (e.g. config values are encrypted) if (await TryHandleSpecialEndpoints(context)) { return; } // Regular endpoint handling using (_activeRequestsCounter.NewContext("Request")) { RequestTimings.GetOrCreate(); // initialize request timing context string methodName = null; // Initialize with empty object for protocol backwards-compatibility. var requestData = new HttpServiceRequest { TracingData = new TracingData() }; object[] argumentsWithDefaults = null; ServiceMethod serviceMethod = null; ServiceCallEvent callEvent = _serverRequestPublisher.GetNewCallEvent(); try { try { await CheckSecureConnection(context); ValidateRequest(context); requestData = await ParseRequest(context); //----------------------------------------------------------------------------------------- // Don't move TracingContext writes main flow, IT have to be here, to avoid side changes //----------------------------------------------------------------------------------------- TracingContext.SetRequestID(requestData.TracingData.RequestID); TracingContext.SpanStartTime = requestData.TracingData.SpanStartTime; TracingContext.AbandonRequestBy = requestData.TracingData.AbandonRequestBy; TracingContext.SetParentSpan( requestData.TracingData.SpanID ?? Guid.NewGuid().ToString("N")); TracingContext.SetOverrides(requestData.Overrides); if (requestData.TracingData.Tags != null) { TracingContext.Tags = new ContextTags(requestData.TracingData.Tags); } TracingContext.AdditionalProperties = requestData.TracingData.AdditionalProperties; callEvent.ServiceMethodSchema = context.Request.IsSecureConnection ? "HTTPS" : "HTTP"; SetCallEventRequestData(callEvent, requestData); serviceMethod = ServiceEndPointDefinition.Resolve(requestData.Target); callEvent.CalledServiceName = serviceMethod.GrainInterfaceType.Name; methodName = serviceMethod.ServiceInterfaceMethod.Name; var arguments = requestData.Target.IsWeaklyTyped ? GetParametersByName(serviceMethod, requestData.Arguments) : requestData.Arguments.Values.Cast <object>().ToArray(); argumentsWithDefaults = GetConvertedAndDefaultArguments(serviceMethod.ServiceInterfaceMethod, arguments); if (_extendedDelayTimeLogging) { callEvent.RecvDateTicks = ticks; callEvent.ReqStartupDeltaTicks = deltaDelayTicks; callEvent.TimeFromLastReq = timeFromLastReq; var outstandingRecvReqs = Interlocked.Read(ref _outstandingRecvRequests); callEvent.OutstandingRecvRequests = outstandingRecvReqs; if (deltaDelayTicks > 10_000_000) { callEvent.CollectionCountGen0 = GC.CollectionCount(0); callEvent.CollectionCountGen1 = GC.CollectionCount(1); callEvent.CollectionCountGen2 = GC.CollectionCount(2); } } } catch (Exception e) { callEvent.Exception = e; if (e is RequestException) { throw; } throw new RequestException("Invalid request", e); } RejectRequestIfLateOrOverloaded(); var responseJson = await GetResponse(context, serviceMethod, requestData, argumentsWithDefaults); if (await TryWriteResponse(context, responseJson, serviceCallEvent: callEvent)) { callEvent.ErrCode = 0; _successCounter.Increment(); } else { _failureCounter.Increment(); } } catch (Exception e) { callEvent.Exception = callEvent.Exception ?? e; _failureCounter.Increment(); Exception ex = GetRelevantException(e); string json = _serializationTime.Time(() => ExceptionSerializer.Serialize(ex)); await TryWriteResponse(context, json, GetExceptionStatusCode(ex), serviceCallEvent : callEvent); } finally { sw.Stop(); callEvent.ActualTotalTime = sw.Elapsed.TotalMilliseconds; _roundtripTime.Record((long)(sw.Elapsed.TotalMilliseconds * 1000000), TimeUnit.Nanoseconds); if (methodName != null) { _endpointContext.Timer(methodName, Unit.Requests) .Record((long)(sw.Elapsed.TotalMilliseconds * 1000000), TimeUnit.Nanoseconds); } _serverRequestPublisher.TryPublish(callEvent, argumentsWithDefaults, serviceMethod); } } } } finally { _stopwatchPool.Return(sw); Interlocked.Decrement(ref _outstandingRecvRequests); } }
private async Task HandleRequest(HttpListenerContext context) { RequestTimings.ClearCurrentTimings(); using (context.Response) { var sw = Stopwatch.StartNew(); // Special endpoints should not be logged/measured/traced like regular endpoints try { foreach (var customEndpoint in CustomEndpoints) { if (await customEndpoint.TryHandle(context, (data, status, type) => TryWriteResponse(context, data, status, type))) { if (RequestTimings.Current.Request.ElapsedMS != null) { _metaEndpointsRoundtripTime.Record((long)RequestTimings.Current.Request.ElapsedMS, TimeUnit.Milliseconds); } return; } } } catch (Exception e) { var ex = GetRelevantException(e); await TryWriteResponse(context, JsonExceptionSerializer.Serialize(ex), GetExceptionStatusCode(ex)); return; } // Regular endpoint handling using (_activeRequestsCounter.NewContext("Request")) { TracingContext.SetUpStorage(); RequestTimings.GetOrCreate(); // initialize request timing context Exception ex; Exception actualException = null; string methodName = null; // Initialize with empty object for protocol backwards-compatibility. var requestData = new HttpServiceRequest { TracingData = new TracingData() }; ServiceMethod serviceMethod = null; try { try { ValidateRequest(context); await CheckSecureConnection(context); requestData = await ParseRequest(context); TracingContext.SetOverrides(requestData.Overrides); serviceMethod = ServiceEndPointDefinition.Resolve(requestData.Target); methodName = serviceMethod.ServiceInterfaceMethod.Name; } catch (Exception e) { actualException = e; if (e is RequestException) { throw; } throw new RequestException("Invalid request", e); } var responseJson = await GetResponse(context, serviceMethod, requestData); await TryWriteResponse(context, responseJson); _successCounter.Increment(); } catch (Exception e) { actualException = actualException ?? e; _failureCounter.Increment(); ex = GetRelevantException(e); string json = _serializationTime.Time(() => JsonExceptionSerializer.Serialize(ex)); await TryWriteResponse(context, json, GetExceptionStatusCode(ex)); } finally { sw.Stop(); _roundtripTime.Record((long)(sw.Elapsed.TotalMilliseconds * 1000000), TimeUnit.Nanoseconds); if (methodName != null) { _endpointContext.Timer(methodName, Unit.Requests).Record((long)(sw.Elapsed.TotalMilliseconds * 1000000), TimeUnit.Nanoseconds); } PublishEvent(requestData, actualException, serviceMethod, sw.Elapsed.TotalMilliseconds); } } } }
public async Task HttpsStoppedListening_FallbackToHttp() { var host = "host1"; var httpsPortOffset = 5; var port = DisposablePort.GetPort().Port; var dict = new Dictionary <string, string> { { "Discovery.Services.DemoService.Source", "Config" }, { "Discovery.Services.DemoService.Hosts", host }, { "Discovery.Services.DemoService.DefaultPort", port.ToString() } }; int httpsTestCount = 0; bool httpsMethodCalled = false; Func <bool, string, HttpMessageHandler> messageHandlerFactory = (_, __) => { var messageHandler = new MockHttpMessageHandler(); messageHandler .When("https://*") .Respond(req => { if (httpsMethodCalled) { throw new HttpRequestException("", new WebException("", WebExceptionStatus.ProtocolError)); } if (req.RequestUri.AbsoluteUri == $"https://{host}:{port + httpsPortOffset}/") { httpsTestCount++; return(HttpResponseFactory.GetResponse(content: "'some HTTPS response'")); } if (req.RequestUri.AbsoluteUri == $"https://{host}:{port + httpsPortOffset}/DemoService.testMethod") { httpsMethodCalled = true; return(HttpResponseFactory.GetResponse(content: "'some HTTPS response'")); } throw new HttpRequestException("Invalid uri"); }); messageHandler .When("http://*") .Respond(req => { if (req.RequestUri.AbsoluteUri == $"http://{host}:{port}/DemoService.testMethod") { return(HttpResponseFactory.GetResponse(content: "'some HTTP response'")); } if (req.RequestUri.AbsoluteUri == $"http://{host}:{port}/") { return(HttpResponseFactory.GetResponse(content: "'{X-Gigya-ServerHostname: someValue}'")); } throw new HttpRequestException("Invalid uri"); }); return(messageHandler); }; using (var kernel = new TestingKernel <ConsoleLog>( k => { k.Rebind <IDiscovery>().To <ServiceDiscovery.Rewrite.Discovery>().InSingletonScope(); k.Rebind <Func <bool, string, HttpMessageHandler> >().ToMethod(c => messageHandlerFactory); }, dict) ) { var providerFactory = kernel.Get <Func <string, ServiceProxyProvider> >(); var serviceProxy = providerFactory("DemoService"); serviceProxy.DefaultPort = port; TracingContext.SetRequestID("1"); var request = new HttpServiceRequest("testMethod", null, new Dictionary <string, object>()); var server = await serviceProxy.Invoke(request, typeof(string)); server.ShouldBe("some HTTP response"); Assert.That(() => httpsTestCount, Is.EqualTo(1).After(10).Seconds.PollEvery(1).Seconds); server = await serviceProxy.Invoke(request, typeof(string)); server.ShouldBe("some HTTPS response"); server = await serviceProxy.Invoke(request, typeof(string)); server.ShouldBe("some HTTP response"); } }
protected override void ExecuteCore() { var group = new ProgressGroup { Status = Strings.UpdatingStatus }; ProgressManager.Current.Register(group); try { foreach (var config in status.TargetChannels) { var channel = ChannelsManager.GetChannelObject(config.ChannelId); try { group.SourceChannelId = config.ChannelId; ChannelContext.Current.ClientContext = new ChannelClientContext(ClientState.Current.Context, config); Logger.Debug("Updating status. Channel = {0}", LogSource.BackgroundTask, config.DisplayName); if (config.IsConnected) { var data = String.Format("wrap_access_token={0}&channels={1}&inreplyto={2}&body={3}", CloudApi.AccessToken, config.ChannelKey, status.InReplyTo, HttpUtility.UrlEncode(status.Status)); HttpServiceRequest.Post(String.Concat(CloudApi.ApiBaseUrl, "send/statusupdate"), data, true); } else { channel.StatusUpdatesChannel.UpdateMyStatus(status.DuckCopy <ChannelStatusUpdate>()); } } catch (Exception ex) { ClientState.Current.ShowMessage( new AppMessage( String.Concat( String.Format(Strings.ErrorOccuredDuringStatusUpdate, channel.Configuration.DisplayName), String.Format(Strings.ServerSaid, ex.Message))) { SourceChannelId = config.ChannelId }, MessageType.Error); throw; } } Thread.CurrentThread.ExecuteOnUIThread(() => ClientState.Current.ShowMessage( new AppMessage(Strings.StatusUpdatedSuccessfully) { EntityId = status.StatusId, EntityType = EntityType.UserStatus }, MessageType.Success)); } finally { group.IsCompleted = true; } }
public async Task HttpsDisabled_NoCertificate_CallSucceeds() { var host = "host1"; var httpsPortOffset = 5; var port = DisposablePort.GetPort().Port; var dict = new Dictionary <string, string> { { "Discovery.Services.DemoService.Source", "Config" }, { "Discovery.Services.DemoService.Hosts", host }, { "Discovery.Services.DemoService.DefaultPort", port.ToString() }, { "Discovery.Services.DemoService.UseHttpsOverride", "false" } }; int httpsTestCount = 0; bool httpsMethodCalled = false; Func <HttpClientConfiguration, HttpMessageHandler> messageHandlerFactory = _ => { var messageHandler = new MockHttpMessageHandler(); messageHandler .When("https://*") .Respond(req => HttpResponseFactory.GetResponseWithException(ExceptionSerializer, new SocketException())); messageHandler .When("http://*") .Respond(req => HttpResponseFactory.GetResponse(content: "'some HTTP response'")); return(messageHandler); }; using (var kernel = new TestingKernel <ConsoleLog>( k => { k.Rebind <IDiscovery>().To <ServiceDiscovery.Rewrite.Discovery>().InSingletonScope(); k.Rebind <Func <HttpClientConfiguration, HttpMessageHandler> >().ToMethod(c => messageHandlerFactory); var certificateLocator = Substitute.For <ICertificateLocator>(); certificateLocator .When(cl => cl.GetCertificate(Arg.Any <string>())) .Do(x => throw new Exception()); k.Rebind <ICertificateLocator>().ToConstant(certificateLocator); var httpsAuthenticator = Substitute.For <IHttpsAuthenticator>(); httpsAuthenticator .When(a => a.AddHttpMessageHandlerAuthentication(Arg.Any <HttpClientHandler>(), Arg.Any <HttpClientConfiguration>())) .Do(x => throw new Exception()); k.Rebind <IHttpsAuthenticator>().ToConstant(httpsAuthenticator); }, dict) ) { var providerFactory = kernel.Get <Func <string, ServiceProxyProvider> >(); var serviceProxy = providerFactory("DemoService"); serviceProxy.DefaultPort = port; TracingContext.SetRequestID("1"); var request = new HttpServiceRequest("testMethod", null, new Dictionary <string, object>()); await serviceProxy.Invoke(request, typeof(string)); } }
public async Task RequestContextOverrideShouldFailOnFirstAttempt() { var port = DisposablePort.GetPort().Port; var dict = new Dictionary <string, string> { { "Discovery.Services.DemoService.Source", "Config" }, { "Discovery.Services.DemoService.Hosts", "notImpotent" }, { "Discovery.Services.DemoService.DefaultPort", port.ToString() } }; int counter = 0; Func <bool, string, HttpMessageHandler> messageHandlerFactory = (_, __) => { var messageHandler = new MockHttpMessageHandler(); messageHandler .When("*") .Respond(req => { if (req.Method == HttpMethod.Get && req.RequestUri.Scheme == "https") { throw new HttpRequestException(); } counter++; throw new HttpRequestException(); }); return(messageHandler); }; using (var kernel = new TestingKernel <ConsoleLog>( k => { k.Rebind <IDiscovery>().To <ServiceDiscovery.Rewrite.Discovery>().InSingletonScope(); k.Rebind <Func <bool, string, HttpMessageHandler> >().ToMethod(c => messageHandlerFactory); }, dict) ) { var providerFactory = kernel.Get <Func <string, ServiceProxyProvider> >(); var serviceProxy = providerFactory("DemoService"); serviceProxy.DefaultPort = port; //Disable TracingContext.SetRequestID("1"); CallContext.FreeNamedDataSlot("#ORL_RC"); string overrideHost = "override-host"; int overridePort = 5318; TracingContext.SetHostOverride("DemoService", overrideHost, overridePort); var request = new HttpServiceRequest("testMethod", null, new Dictionary <string, object>()); for (int i = 0; i < 3; i++) { Func <Task> act = () => serviceProxy.Invoke(request, typeof(string)); await act.ShouldThrowAsync <HttpRequestException>(); } counter.ShouldBe(3); } }
public async Task HttpsListening_CallHttpsAfterFirstHttpCall() { var host = "host1"; var httpsPortOffset = 5; var port = DisposablePort.GetPort().Port; var dict = new Dictionary <string, string> { { "Discovery.Services.DemoService.Source", "Config" }, { "Discovery.Services.DemoService.Hosts", host }, { "Discovery.Services.DemoService.DefaultPort", port.ToString() }, { "Discovery.Services.DemoService.TryHttps", "true" } }; int httpsTestCount = 0; Func <HttpClientConfiguration, HttpMessageHandler> messageHandlerFactory = _ => { var messageHandler = new MockHttpMessageHandler(); messageHandler .When("https://*") .Respond(req => { if (req.RequestUri.AbsoluteUri == $"https://{host}:{port + httpsPortOffset}/") { httpsTestCount++; return(HttpResponseFactory.GetResponse(content: "'some HTTPS response'")); } if (req.RequestUri.AbsoluteUri == $"https://{host}:{port + httpsPortOffset}/DemoService.testMethod") { return(HttpResponseFactory.GetResponse(content: "'some HTTPS response'")); } throw new HttpRequestException("Invalid uri"); }); messageHandler .When("http://*") .Respond(req => { if (req.RequestUri.AbsoluteUri == $"http://{host}:{port}/DemoService.testMethod") { return(HttpResponseFactory.GetResponse(content: "'some HTTP response'")); } throw new HttpRequestException("Invalid uri"); }); return(messageHandler); }; using (var kernel = new TestingKernel <ConsoleLog>( k => { k.Rebind <IDiscovery>().To <ServiceDiscovery.Rewrite.Discovery>().InSingletonScope(); k.Rebind <Func <HttpClientConfiguration, HttpMessageHandler> >().ToMethod(c => messageHandlerFactory); var getConfig = k.Get <Func <DiscoveryConfig> >(); k.Rebind <Func <DiscoveryConfig> >().ToMethod(c => { var config = getConfig(); return(() => config); }); }, dict) ) { var providerFactory = kernel.Get <Func <string, ServiceProxyProvider> >(); var serviceProxy = providerFactory("DemoService"); serviceProxy.DefaultPort = port; TracingContext.SetRequestID("1"); var request = new HttpServiceRequest("testMethod", null, new Dictionary <string, object>()); for (int i = 0; i < 10; i++) { bool httpsTestFinished = httpsTestCount > 0; var server = await serviceProxy.Invoke(request, typeof(string)); server.ShouldBe(httpsTestFinished ? "some HTTPS response" : "some HTTP response"); } Assert.That(() => httpsTestCount, Is.EqualTo(1).After(10).Seconds.PollEvery(1).Seconds); } }
public async Task ServiceProxyRpcMessageShouldRemainSame() { const string serviceName = "DemoService"; int defaultPort = DisposablePort.GetPort().Port; var dict = new Dictionary <string, string> { { $"Discovery.Services.{serviceName}.Source", "Config" }, { $"Discovery.Services.{serviceName}.Hosts", "host1" }, { $"Discovery.Services.{serviceName}.DefaultPort", defaultPort.ToString() } }; Uri uri = null; string requestMessage = null; Func <HttpClientConfiguration, HttpMessageHandler> messageHandlerFactory = _ => { var messageHandler = new MockHttpMessageHandler(); messageHandler .When("*").Respond(async req => { requestMessage = await req.Content.ReadAsStringAsync(); uri = req.RequestUri; return(HttpResponseFactory.GetResponse(HttpStatusCode.Accepted)); }); return(messageHandler); }; using (var kernel = new TestingKernel <ConsoleLog>(k => { k.Rebind <IDiscovery>().To <ServiceDiscovery.Rewrite.Discovery>().InSingletonScope(); k.Rebind <Func <HttpClientConfiguration, HttpMessageHandler> >().ToMethod(c => messageHandlerFactory); }, dict)) { var providerFactory = kernel.Get <Func <string, ServiceProxyProvider> >(); TracingContext.SetRequestID("g"); var serviceProxy = providerFactory(serviceName); string expectedHost = "override-host"; int expectedPort = DisposablePort.GetPort().Port; TracingContext.SetHostOverride(serviceName, expectedHost, expectedPort); var request = new HttpServiceRequest("testMethod", null, new Dictionary <string, object>()); using (TracingContext.Tags.SetUnencryptedTag("test", 1)) using (TracingContext.SuppressCaching(CacheSuppress.RecursiveAllDownstreamServices)) await serviceProxy.Invoke(request, typeof(string)); var body = requestMessage; Console.WriteLine($"error: {body}"); JsonConvert.DeserializeObject <GigyaRequestProtocol>(body, new JsonSerializerSettings() { MissingMemberHandling = MissingMemberHandling.Error }); uri.Host.ShouldBe(expectedHost); uri.Port.ShouldBe(expectedPort); } }
private Task <T> SendRequest <T>(HttpServiceRequest requestMessage) { return(this.httpService.SendRequestAsync <T>(requestMessage)); }
private async Task HandleRequest(HttpListenerContext context) { RequestTimings.ClearCurrentTimings(); using (context.Response) { var sw = Stopwatch.StartNew(); // Special endpoints should not be logged/measured/traced like regular endpoints if (await TryHandleSpecialEndpoints(context)) { return; } // Regular endpoint handling using (_activeRequestsCounter.NewContext("Request")) { RequestTimings.GetOrCreate(); // initialize request timing context string methodName = null; // Initialize with empty object for protocol backwards-compatibility. var requestData = new HttpServiceRequest { TracingData = new TracingData() }; object[] argumentsWithDefaults = null; ServiceMethod serviceMethod = null; ServiceCallEvent callEvent = _serverRequestPublisher.GetNewCallEvent(); try { try { ValidateRequest(context); await CheckSecureConnection(context); requestData = await ParseRequest(context); //----------------------------------------------------------------------------------------- // Don't move TracingContext writes main flow, IT have to be here, to avoid side changes //----------------------------------------------------------------------------------------- TracingContext.SetRequestID(requestData.TracingData.RequestID); TracingContext.SpanStartTime = requestData.TracingData.SpanStartTime; TracingContext.AbandonRequestBy = requestData.TracingData.AbandonRequestBy; TracingContext.SetSpan(null, requestData.TracingData.SpanID ?? Guid.NewGuid().ToString("N")); SetCallEventRequestData(callEvent, requestData); TracingContext.SetOverrides(requestData.Overrides); serviceMethod = ServiceEndPointDefinition.Resolve(requestData.Target); callEvent.CalledServiceName = serviceMethod.GrainInterfaceType.Name; methodName = serviceMethod.ServiceInterfaceMethod.Name; var arguments = requestData.Target.IsWeaklyTyped ? GetParametersByName(serviceMethod, requestData.Arguments) : requestData.Arguments.Values.Cast <object>().ToArray(); argumentsWithDefaults = GetConvertedAndDefaultArguments(serviceMethod.ServiceInterfaceMethod, arguments); } catch (Exception e) { callEvent.Exception = e; if (e is RequestException) { throw; } throw new RequestException("Invalid request", e); } RejectRequestIfLateOrOverloaded(); var responseJson = await GetResponse(context, serviceMethod, requestData, argumentsWithDefaults); if (await TryWriteResponse(context, responseJson, serviceCallEvent: callEvent)) { callEvent.ErrCode = 0; _successCounter.Increment(); } else { _failureCounter.Increment(); } } catch (Exception e) { callEvent.Exception = callEvent.Exception ?? e; _failureCounter.Increment(); Exception ex = GetRelevantException(e); string json = _serializationTime.Time(() => ExceptionSerializer.Serialize(ex)); await TryWriteResponse(context, json, GetExceptionStatusCode(ex), serviceCallEvent : callEvent); } finally { sw.Stop(); callEvent.ActualTotalTime = sw.Elapsed.TotalMilliseconds; _roundtripTime.Record((long)(sw.Elapsed.TotalMilliseconds * 1000000), TimeUnit.Nanoseconds); if (methodName != null) { _endpointContext.Timer(methodName, Unit.Requests).Record((long)(sw.Elapsed.TotalMilliseconds * 1000000), TimeUnit.Nanoseconds); } _serverRequestPublisher.TryPublish(callEvent, argumentsWithDefaults, serviceMethod); } } } }
private async Task <string> GetResponse(HttpListenerContext context, ServiceMethod serviceMethod, HttpServiceRequest requestData) { string response; InvocationResult invocationResult; if (requestData.Target.IsWeaklyTyped) { invocationResult = await Activator.Invoke(serviceMethod, requestData.Arguments); response = _serializationTime.Time(() => JsonConvert.SerializeObject(invocationResult.Result, serviceMethod.ServiceInterfaceMethod.ReturnType, JsonSettingsWeak)); } else { invocationResult = await Activator.Invoke(serviceMethod, requestData.Arguments.Values.Cast <object>().ToArray()); response = _serializationTime.Time(() => JsonConvert.SerializeObject(invocationResult.Result, serviceMethod.ServiceInterfaceMethod.ReturnType, JsonSettings)); } context.Response.Headers.Add(GigyaHttpHeaders.ExecutionTime, invocationResult.ExecutionTime.ToString()); return(response); }