|
| 1 | +# Take Sentry's SerializableHttpContent, convert it to a string, and send via PowerShell's Invoke-WebRequest, |
| 2 | +# then translate the response back to a .NET HttpResponseMessage. |
| 3 | +# There are limited options to perform synchronous operations in Windows PowerShell 5.1 on .NET 4.6, so this is a workaround. |
| 4 | +class SynchronousTransport : Sentry.Http.HttpTransportBase, Sentry.Extensibility.ITransport |
| 5 | +{ |
| 6 | + hidden [Sentry.Extensibility.IDiagnosticLogger] $logger |
| 7 | + hidden [System.Reflection.MethodInfo] $ProcessEnvelope |
| 8 | + hidden [System.Reflection.MethodInfo] $CreateRequest |
| 9 | + hidden [System.Reflection.MethodInfo] $SerializeToStream |
| 10 | + |
| 11 | + SynchronousTransport([Sentry.SentryOptions] $options) : base($options) |
| 12 | + { |
| 13 | + $this.logger = $options.DiagnosticLogger |
| 14 | + |
| 15 | + # These are internal methods, so we need to use reflection to access them. |
| 16 | + $instanceMethod = [System.Reflection.BindingFlags]::Instance + [System.Reflection.BindingFlags]::NonPublic + [System.Reflection.BindingFlags]::Public; |
| 17 | + $this.ProcessEnvelope = [Sentry.Http.HttpTransportBase].GetMethod('ProcessEnvelope', $instanceMethod) |
| 18 | + $this.CreateRequest = [Sentry.Http.HttpTransportBase].GetMethod('CreateRequest', $instanceMethod) |
| 19 | + $EnvelopeHttpContentType = [Sentry.SentrySdk].Assembly.GetType('Sentry.Internal.Http.EnvelopeHttpContent') |
| 20 | + $this.SerializeToStream = $EnvelopeHttpContentType.GetMethod('SerializeToStream', $instanceMethod) |
| 21 | + } |
| 22 | + |
| 23 | + [System.Threading.Tasks.Task] SendEnvelopeAsync([Sentry.Protocol.Envelopes.Envelope] $envelope, [System.Threading.CancellationToken]$cancellationToken = [System.Threading.CancellationToken]::None) |
| 24 | + { |
| 25 | + $processedEnvelope = $this.ProcessEnvelope.Invoke($this, @($envelope)) |
| 26 | + if ($processedEnvelope.Items.count -gt 0) |
| 27 | + { |
| 28 | + $request = $this.CreateRequest.Invoke($this, @($processedEnvelope)) |
| 29 | + |
| 30 | + $headers = @{} |
| 31 | + foreach ($header in $request.Headers) |
| 32 | + { |
| 33 | + $Key = $header.Key |
| 34 | + $Value = $header.Value.Trim() -join ', ' |
| 35 | + $headers[$Key] = $Value |
| 36 | + } |
| 37 | + |
| 38 | + $memoryStream = [System.IO.MemoryStream]::new() |
| 39 | + $this.SerializeToStream.Invoke($request.Content, @($memoryStream, $null, $cancellationToken)) |
| 40 | + $memoryStream.Position = 0 |
| 41 | + |
| 42 | + $reader = New-Object System.IO.StreamReader($memoryStream) |
| 43 | + $content = $reader.ReadToEnd() |
| 44 | + $reader.Close() |
| 45 | + |
| 46 | + $this.logger.Log([Sentry.SentryLevel]::Debug, 'Sending content synchronously, Content-Length: {0}', $null, $content.Length) |
| 47 | + |
| 48 | + $ProgressPreference = 'SilentlyContinue' |
| 49 | + $psResponse = Invoke-WebRequest -Uri $request.RequestUri -Method $request.Method.Method -Headers $headers -Body $content -UseBasicParsing |
| 50 | + |
| 51 | + $response = [System.Net.Http.HttpResponseMessage]::new($psResponse.StatusCode) |
| 52 | + $contentType = $psResponse.Headers['Content-Type'] |
| 53 | + if ($null -eq $contentType) |
| 54 | + { |
| 55 | + $contentType = 'application/json' |
| 56 | + } |
| 57 | + $response.Content = [System.Net.Http.StringContent]::new($psResponse.Content, [System.Text.Encoding]::UTF8, $contentType) |
| 58 | + |
| 59 | + foreach ($header in $psResponse.Headers.GetEnumerator()) |
| 60 | + { |
| 61 | + $response.Headers.TryAddWithoutValidation($header.Key, $header.Value) |
| 62 | + } |
| 63 | + |
| 64 | + $this.HandleResponse($response, $processedEnvelope) |
| 65 | + } |
| 66 | + |
| 67 | + return [System.Threading.Tasks.Task]::CompletedTask |
| 68 | + } |
| 69 | +} |
0 commit comments