using System; using System.Collections.Generic; using System.Net; using System.Net.Http; using Amazon.Runtime.Internal.Util; using Amazon.XRay.Recorder.Core; using Amazon.XRay.Recorder.Core.Exceptions; using Amazon.XRay.Recorder.Core.Internal.Entities; namespace Amazon.XRay.Recorder.Handlers.System.Net.Utils { public static class RequestUtil { private static readonly Logger _logger = Runtime.Internal.Util.Logger.GetLogger(typeof(RequestUtil)); /// /// Collects information from and adds a tracing header to the request. /// Depending on the flag sanitizeHttpRequestTracing the query string on http request is stripped before tracing is submitted. /// /// An instance of /// value internal static void ProcessRequest(WebRequest request, bool sanitizeHttpRequestTracing = false) { ProcessRequest(request.RequestUri, request.Method, header => request.Headers.Add(TraceHeader.HeaderKey, header), sanitizeHttpRequestTracing); } /// /// Collects information from and adds a tracing header to the request. /// Depending on the flag sanitizeHttpRequestTracing the query string on http request is stripped before tracing is submitted. /// /// An instance of /// value internal static void ProcessRequest(HttpRequestMessage request, bool sanitizeHttpRequestTracing = false) { ProcessRequest(request.RequestUri, request.Method.Method, AddOrReplaceHeader, sanitizeHttpRequestTracing); void AddOrReplaceHeader(string header) { request.Headers.Remove(TraceHeader.HeaderKey); request.Headers.Add(TraceHeader.HeaderKey, header); } } /// /// Collects information from the response and adds to instance. /// /// An instance of internal static void ProcessResponse(HttpWebResponse response) { ProcessResponse(response.StatusCode, response.ContentLength); } /// /// Collects information from the response and adds to instance. /// /// An instance of internal static void ProcessResponse(HttpResponseMessage response) { ProcessResponse(response.StatusCode, response.Content.Headers.ContentLength); } private static void ProcessRequest(Uri uri, string method, Action addHeaderAction, bool sanitizeHttpRequestTracing) { if (AWSXRayRecorder.Instance.IsTracingDisabled()) { _logger.DebugFormat("Tracing is disabled. Not starting a subsegment on HTTP request."); return; } var recorder = AWSXRayRecorder.Instance; recorder.BeginSubsegment(uri.Host); recorder.SetNamespace("remote"); var requestInformation = new Dictionary { ["url"] = sanitizeHttpRequestTracing ? uri.AbsoluteUri.Split(new[] { '?' })[0] : uri.AbsoluteUri, ["method"] = method }; recorder.AddHttpInformation("request", requestInformation); try { if (TraceHeader.TryParse(recorder.GetEntity(), out var header)) { addHeaderAction(header.ToString()); } } catch (EntityNotAvailableException e) { recorder.TraceContext.HandleEntityMissing(recorder,e, "Failed to get entity since it is not available in trace context while processing http request."); } } private static void ProcessResponse(HttpStatusCode httpStatusCode, long? contentLength) { if (AWSXRayRecorder.Instance.IsTracingDisabled()) { _logger.DebugFormat("Tracing is disabled. Not ending a subsegment on HTTP response."); return; } var statusCode = (int)httpStatusCode; var responseInformation = new Dictionary { ["status"] = statusCode }; if (statusCode >= 400 && statusCode <= 499) { AWSXRayRecorder.Instance.MarkError(); if (statusCode == 429) { AWSXRayRecorder.Instance.MarkThrottle(); } } else if (statusCode >= 500 && statusCode <= 599) { AWSXRayRecorder.Instance.MarkFault(); } responseInformation["content_length"] = contentLength; AWSXRayRecorder.Instance.AddHttpInformation("response", responseInformation); } } }