예제 #1
0
        public override BodyDataTransformResult Transform(HttpRequestRecord record, byte[] body, StringValues contentTypeHeaderValues)
        {
            var data = MessagePack.LZ4MessagePackSerializer.Deserialize <MyClass>(body, MessagePack.Resolvers.ContractlessStandardResolver.Instance);
            var json = MessagePack.MessagePackSerializer.ToJson <MyClass>(data, MessagePack.Resolvers.ContractlessStandardResolver.Instance);

            return(new BodyDataTransformResult(new UTF8Encoding(false).GetBytes(json), contentTypeHeaderValues.ToString(), "application/json"));
        }
예제 #2
0
        public bool TryTransform(HttpRequestRecord record, ReadOnlySpan <byte> body, StringValues contentTypeHeaderValues, out BodyDataTransformResult result)
        {
            var json = MessagePackSerializer.ConvertToJson(body.ToArray(), MessagePack.Resolvers.ContractlessStandardResolver.Options);

            result = new BodyDataTransformResult(Encoding.UTF8.GetBytes(json), contentTypeHeaderValues.ToString(), "application/json");
            return(true);
        }
예제 #3
0
 public async Task UpdateAsync(HttpRequestRecord entry)
 {
     await Task.WhenAll(
         _redis.StringSetAsync(GetRedisKey($"RecordEntry?{entry.Id}"), Serialize(entry)),
         _redis.StringSetAsync(GetRedisKey($"RecordEntryInfo?{entry.Id}"), Serialize(HttpRequestRecordInfo.CreateFromRecord(entry)))
         );
 }
예제 #4
0
        public static BodyDataPayload CreateFromRecord(HttpRequestRecord record, IDictionary <string, StringValues>?headers, ReadOnlySpan <byte> body, IBodyDataTransformer transformer)
        {
            if (body.IsEmpty)
            {
                return(new BodyDataPayload(Convert.ToBase64String(Array.Empty <byte>()), true, ""));
            }

            var payloadBody                = body;
            var payloadBodyContentType     = string.Empty;
            var transformedBodyContentType = string.Empty;

            if (headers != null && headers.TryGetValue("Content-Type", out var contentType))
            {
                if (transformer.TryTransform(record, body, contentType, out var result))
                {
                    payloadBodyContentType     = result.TransformedContentType;
                    transformedBodyContentType = result.TransformedContentType;
                    payloadBody = result.Body;
                }
            }

            if (payloadBodyContentType.StartsWith("text/") ||
                payloadBodyContentType.StartsWith("application/json") ||
                payloadBodyContentType.StartsWith("application/x-www-form-urlencoded"))
            {
                return(new BodyDataPayload(Encoding.UTF8.GetString(payloadBody), false, transformedBodyContentType));
            }
            else
            {
                return(new BodyDataPayload(Convert.ToBase64String(payloadBody), true, transformedBodyContentType));
            }
        }
예제 #5
0
        private async Task PostprocessAsync(HttpContext context, RinOptions options, HttpRequestRecord record)
        {
            var request  = context.Request;
            var response = context.Response;

            record.Processing.Complete();

            record.ResponseStatusCode = response.StatusCode;
            record.ResponseHeaders    = response.Headers.ToDictionary(k => k.Key, v => v.Value);

            if (options.RequestRecorder.EnableBodyCapturing)
            {
                var memoryStreamRequestBody = new MemoryStream();
                request.Body.Position = 0; // rewind the stream to head
                await request.Body.CopyToAsync(memoryStreamRequestBody);

                var feature = context.Features.Get <IRinRequestRecordingFeature>();

                await _eventBusStoreBody.PostAsync(new StoreBodyEventMessage(StoreBodyEvent.Request, record.Id, memoryStreamRequestBody.ToArray()));

                await _eventBusStoreBody.PostAsync(new StoreBodyEventMessage(StoreBodyEvent.Response, record.Id, feature.ResponseDataStream.GetCapturedData()));
            }

            var exceptionFeature = context.Features.Get <IExceptionHandlerFeature>();

            if (exceptionFeature != null)
            {
                record.Exception = new ExceptionData(exceptionFeature.Error);
            }
        }
예제 #6
0
        private void FiddlerBeforeResponse(Session session)
        {
            Uri uri = new Uri(session.fullUrl);

            if (FileExtensionsToExclude.Count > 0 && FileExtensionsToExclude.Any(x => string.Equals(x, Path.GetExtension(uri.AbsolutePath), StringComparison.OrdinalIgnoreCase)))
            {
                return;
            }

            if (HostNamesToCollect.Count > 0 && !HostNamesToCollect.Any(x => string.Equals(x, GetHostAndPort(uri), StringComparison.OrdinalIgnoreCase)))
            {
                return;
            }

            if (RegexToExcludeUrls.Count > 0 && RegexToExcludeUrls.Any(x => Regex.IsMatch(uri.ToString(), x, RegexOptions.IgnoreCase)))
            {
                return;
            }

            NameValueCollection queryData = HttpUtility.ParseQueryString(uri.Query);
            string method = session.oRequest.headers.HTTPMethod;

            if (HttpMethodsToCollect.Count > 0 && !HttpMethodsToCollect.Any(x => string.Equals(x, method, StringComparison.OrdinalIgnoreCase)))
            {
                return;
            }

            NameValueCollection requestHeaders = new NameValueCollection();

            foreach (HTTPHeaderItem httpRequestHeader in session.oRequest.headers)
            {
                requestHeaders.Add(httpRequestHeader.Name, httpRequestHeader.Value);
            }

            string requestContent     = (session.RequestBody != null) && (session.RequestBody.Length > 0) ? CONFIG.oHeaderEncoding.GetString(session.RequestBody) : null;
            string requestContentType = requestHeaders["Content-Type"] ?? string.Empty;

            NameValueCollection postData = !string.Equals(method, "POST", StringComparison.OrdinalIgnoreCase) || requestContentType == "application/json" || string.IsNullOrWhiteSpace(requestContent) ? null : GetRequestPostAsDictionary(requestContent);
            int responseStatus           = session.responseCode;

            NameValueCollection responseHeaders = new NameValueCollection();

            foreach (HTTPHeaderItem httpResponseHeader in session.oResponse.headers)
            {
                responseHeaders.Add(httpResponseHeader.Name, httpResponseHeader.Value);
            }

            string responseContent = (session.ResponseBody != null && session.ResponseBody.Length > 0) ? CONFIG.oHeaderEncoding.GetString(session.ResponseBody) : null;

            HttpRequestRecord httpRequestRecord = new HttpRequestRecord(uri, queryData, method, requestHeaders, requestContent, requestContentType, postData, responseStatus, responseHeaders, responseContent);

            m_HttpRequestRecordCollection.Add(httpRequestRecord);

            HttpRequestRecordReceived(this, httpRequestRecord);
        }
예제 #7
0
        public BodyDataTransformResult Transform(HttpRequestRecord record, byte[] body, StringValues contentTypeHeaderValues)
        {
            var transformer = _transformers.FirstOrDefault(x => x.CanTransform(record, contentTypeHeaderValues));

            if (transformer != null)
            {
                return(transformer.Transform(record, body, contentTypeHeaderValues));
            }

            return(new BodyDataTransformResult(body, contentTypeHeaderValues.ToString(), null));
        }
예제 #8
0
        public bool TryTransform(HttpRequestRecord record, ReadOnlySpan <byte> body, StringValues contentTypeHeaderValues, out BodyDataTransformResult result)
        {
            var transformer = _transformers.FirstOrDefault(x => x.CanTransform(record, contentTypeHeaderValues));

            if (transformer != null)
            {
                return(transformer.TryTransform(record, body, contentTypeHeaderValues, out result));
            }

            result = default;
            return(false);
        }
        public bool CanTransform(HttpRequestRecord record, StringValues contentTypeHeaderValues)
        {
            // NOTE: Currently, this transformer can handle only Unary request.
            var methodHandler = _serviceDefinition.MethodHandlers.FirstOrDefault(x => string.Concat("/" + x.ServiceName, "/", x.MethodName) == record.Path);

            if (methodHandler == null || methodHandler.MethodType != MethodType.Unary)
            {
                return(false);
            }

            return(contentTypeHeaderValues.Any(x => x == "application/grpc"));
        }
예제 #10
0
        public async Task AddAsync(HttpRequestRecord entry)
        {
            await Task.WhenAll(
                _redis.ListLeftPushAsync(GetRedisKey($"Records"), entry.Id),
                _redis.StringSetAsync(GetRedisKey($"RecordEntry?{entry.Id}"), Serialize(entry), _options.Expiry),
                _redis.StringSetAsync(GetRedisKey($"RecordEntryInfo?{entry.Id}"), Serialize(HttpRequestRecordInfo.CreateFromRecord(entry)), _options.Expiry)
                );

            await Task.WhenAll(
                _redis.ListTrimAsync(GetRedisKey($"Records"), 0, _rinOptions.RequestRecorder.RetentionMaxRequests),
                _redis.KeyExpireAsync(GetRedisKey($"Records"), _options.Expiry)
                );
        }
예제 #11
0
        private void AddRecordToListBox(HttpRequestRecord record)
        {
            MethodInvoker addListBoxItem = () => listBoxRecord.Items.Add(string.Format("{0}{1} : {2}", record.Method, (record.ResponseStatus > 0) ? string.Format("({0} {1})", record.ResponseStatus, Enum.GetName(typeof(System.Net.HttpStatusCode), record.ResponseStatus)) : null, record.Uri.AbsoluteUri));

            if (listBoxRecord.InvokeRequired)
            {
                listBoxRecord.Invoke(new MethodInvoker(addListBoxItem));
            }
            else
            {
                addListBoxItem();
            }
        }
예제 #12
0
        public async Task InvokeAsync(HttpContext context, RinOptions options)
        {
            var request  = context.Request;
            var response = context.Response;

            if (request.Path.StartsWithSegments(options.Inspector.MountPath) || (options.RequestRecorder.Excludes.Any(x => x.Invoke(request))))
            {
                await _next(context);

                return;
            }

            var timelineRoot = TimelineScope.Prepare();

            HttpRequestRecord record = default;

            try
            {
                record = await PreprocessAsync(context, options, timelineRoot);
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "Unhandled Exception was thrown until pre-processing");
            }

            try
            {
                await _next(context);
            }
            catch (Exception ex)
            {
                if (record != null)
                {
                    record.Exception = new ExceptionData(ex);
                }
                throw;
            }
            finally
            {
                try
                {
                    await PostprocessAsync(context, options, record);
                }
                catch (Exception ex)
                {
                    _logger.LogError(ex, "Unhandled Exception was thrown until post-processing");
                }
            }
        }
예제 #13
0
 public Task UpdateAsync(HttpRequestRecord record)
 {
     _lock.EnterWriteLock();
     try
     {
         if (_entries.TryGetValue(record.Id, out var entry))
         {
             entry.Record = record;
         }
     }
     finally
     {
         _lock.ExitWriteLock();
     }
     return(Task.CompletedTask);
 }
예제 #14
0
        private void btnLoadCollectedData_Click(object sender, EventArgs e)
        {
            if (ofdCollectedData.ShowDialog() == DialogResult.OK)
            {
                HttpRequestRecordCollection httpRequestRecordCollection = m_HttpRequestRecordManager.Load(ofdCollectedData.FileName);

                m_FiddlerHttpRequestRecordCollector.SetCollectedRecords(httpRequestRecordCollection);

                listBoxRecord.Items.Clear();

                for (int i = 0; i < httpRequestRecordCollection.Count; i++)
                {
                    HttpRequestRecord httpRequestRecord = httpRequestRecordCollection[i];

                    AddRecordToListBox(httpRequestRecord);
                }
            }
        }
예제 #15
0
        private async Task <HttpRequestRecord> PreprocessAsync(HttpContext context, RinOptions options, ITimelineScope timelineRoot)
        {
            var request  = context.Request;
            var response = context.Response;

            var record = new HttpRequestRecord()
            {
                Id                = Guid.NewGuid().ToString(),
                IsHttps           = request.IsHttps,
                Host              = request.Host.Value,
                QueryString       = request.QueryString.Value,
                Path              = request.Path,
                Method            = request.Method,
                RequestReceivedAt = DateTimeOffset.Now,
                RequestHeaders    = request.Headers.ToDictionary(k => k.Key, v => v.Value),
                RemoteIpAddress   = request.HttpContext.Connection.RemoteIpAddress,
                Timeline          = timelineRoot,
            };

            // Set Rin recorder feature.
            var feature = new RinRequestRecordingFeature(record);;

            _recordingFeatureAccessor.SetValue(feature);
            context.Features.Set <IRinRequestRecordingFeature>(feature);

            await _eventBus.PostAsync(new RequestEventMessage(EventSourceName, record, RequestEvent.BeginRequest));

            // Set a current Rin request ID to response header.
            context.Response.Headers.Add("X-Rin-Request-Id", record.Id);

            if (options.RequestRecorder.EnableBodyCapturing)
            {
                context.EnableResponseDataCapturing();
                request.EnableBuffering();
            }
            response.OnStarting(OnStarting, record);
            response.OnCompleted(OnCompleted, record);

            // Execute pipeline middlewares.
            record.Processing = TimelineScope.Create("Processing", TimelineEventCategory.AspNetCoreCommon);

            return(record);
        }
예제 #16
0
        private List <HttpRequestWorker> CreateHttpRequestWorkers(int maxSleepTime, Random random, int minSleepTime)
        {
            List <HttpRequestWorker> httpRequestWorkers = new List <HttpRequestWorker>(m_HttpRequestRecords.Count);

            for (int i = 0; i < m_HttpRequestRecords.Count; i++)
            {
                HttpRequestRecord httpRequestRecord = m_HttpRequestRecords[i];

                HttpRequestWorker httpRequestWorker = new HttpRequestWorker(
                    httpRequestRecord,
                    maxSleepTime == 0 ? random.Next(0, minSleepTime) : random.Next(minSleepTime, maxSleepTime),
                    50);
                httpRequestWorker.HttpRequestProcessed += (worker, result) =>
                {
                    MethodInvoker addListViewItem = () =>
                    {
                        ListViewItem item = new ListViewItem(result.HttpRequestRecord.Uri.ToString());
                        item.SubItems.Add(result.Success ? "Success" : "Fail");
                        item.SubItems.Add(GetHttpStatusText(result.HttpResponseStatusCode));
                        item.SubItems.Add(result.ElapsedMilliseconds.ToString(CultureInfo.InvariantCulture));
                        lvRequests.Items.Add(item);
                    };

                    if (result.Success)
                    {
                        Interlocked.Increment(ref m_SuccessfulRequestCount);
                    }

                    if (lvRequests.InvokeRequired)
                    {
                        lvRequests.Invoke(new MethodInvoker(addListViewItem));
                    }
                    else
                    {
                        addListViewItem();
                    }
                };

                httpRequestWorkers.Add(httpRequestWorker);
            }

            return(httpRequestWorkers);
        }
예제 #17
0
        public static BodyDataPayload CreateFromRecord(HttpRequestRecord record, IDictionary <string, StringValues> headers, byte[] body, IBodyDataTransformer transformer)
        {
            if (headers.TryGetValue("Content-Type", out var contentType))
            {
                var result = transformer.Transform(record, body, contentType);

                if (result.ContentType.StartsWith("text/") ||
                    result.ContentType.StartsWith("application/json") ||
                    result.ContentType.StartsWith("text/json") ||
                    result.ContentType.StartsWith("application/x-www-form-urlencoded"))
                {
                    return(new BodyDataPayload(new UTF8Encoding(false).GetString(result.Body), false, result.TransformedContentType ?? ""));
                }
                else
                {
                    return(new BodyDataPayload(Convert.ToBase64String(result.Body), true, result.TransformedContentType ?? ""));
                }
            }

            return(new BodyDataPayload(Convert.ToBase64String(body), true, ""));
        }
예제 #18
0
        public RequestRecordDetailPayload(HttpRequestRecord record)
        {
            Id                 = record.Id;
            ParentId           = record.ParentId;
            IsCompleted        = record.IsCompleted;
            IsHttps            = record.IsHttps;
            Host               = record.Host.Value;
            Method             = record.Method;
            Path               = record.Path;
            QueryString        = record.QueryString.Value;
            ResponseStatusCode = record.ResponseStatusCode;

            RemoteIpAddress         = record.RemoteIpAddress.ToString();
            RequestHeaders          = record.RequestHeaders;
            ResponseHeaders         = record.ResponseHeaders;
            RequestReceivedAt       = record.RequestReceivedAt;
            TransferringCompletedAt = record.TransferringCompletedAt;

            Exception = record.Exception;
            Timeline  = new TimelineData(record.Timeline);
        }
        public bool TryTransform(HttpRequestRecord record, ReadOnlySpan <byte> body, StringValues contentTypeHeaderValues, out BodyDataTransformResult result)
        {
            var methodHandler = _serviceDefinition.MethodHandlers.FirstOrDefault(x => string.Concat("/" + x.ServiceName, "/", x.MethodName) == record.Path);

            if (methodHandler == null)
            {
                result = default;
                return(false);
            }

            try
            {
                var deserialized = MessagePackSerializer.Deserialize(methodHandler.UnwrappedResponseType, body.Slice(5).ToArray() /* Skip gRPC Compressed Flag + Message length */, _serializerOptions);
                result = new BodyDataTransformResult(Encoding.UTF8.GetBytes(JsonSerializer.Serialize(deserialized, RinMagicOnionSupportJsonSerializerOptions.Default)), "application/grpc", "application/json");
                return(true);
            }
            catch
            {
                result = default;
                return(false);
            }
        }
예제 #20
0
        public Task AddAsync(HttpRequestRecord record)
        {
            _lock.EnterWriteLock();
            try
            {
                _entries[record.Id] = new RecordEntry {
                    Record = record
                };
                _entryIds.Enqueue(record.Id);

                if (_entryIds.Count > _retentionMaxRequests)
                {
                    var deletedKey = _entryIds.Dequeue();
                    _entries.Remove(deletedKey);
                }
            }
            finally
            {
                _lock.ExitWriteLock();
            }
            return(Task.CompletedTask);
        }
예제 #21
0
 public RinRequestRecordingFeature(HttpRequestRecord record)
 {
     Record = record;
 }
예제 #22
0
 public abstract BodyDataTransformResult Transform(HttpRequestRecord record, byte[] body, StringValues contentTypeHeaderValues);
예제 #23
0
 public bool CanTransform(HttpRequestRecord record, StringValues contentTypeHeaderValues)
 {
     return(true);
 }
예제 #24
0
 public RequestEventMessage(string eventSource, HttpRequestRecord value, RequestEvent requestEvent)
 {
     EventSource = eventSource;
     Value       = value;
     Event       = requestEvent;
 }
예제 #25
0
 public bool CanTransform(HttpRequestRecord record, StringValues contentTypeHeaderValues)
 {
     return(contentTypeHeaderValues.Any(x => x == "application/x-msgpack"));
 }
예제 #26
0
 public abstract bool CanTransform(HttpRequestRecord record, StringValues contentTypeHeaderValues);
예제 #27
0
 private void FiddlerHttpRequestRecordCollectorHttpRequestRecordReceived(FiddlerHttpRequestRecordCollector collector, HttpRequestRecord record)
 {
     AddRecordToListBox(record);
 }