public sealed override async Task <InputFormatterResult> ReadRequestBodyAsync(InputFormatterContext context, Encoding encoding) { if (context == null) { throw new ArgumentNullException(nameof(context)); } if (encoding == null) { throw new ArgumentNullException(nameof(encoding)); } var httpContext = context.HttpContext; var inputStream = GetInputStream(httpContext, encoding); object model; try { model = await Serialization.Serializer.Json.DeserializeAsync(inputStream, context.ModelType); } catch (JsonException exception) { var path = exception.Path; var formatterException = new InputFormatterException(exception.Message, exception); context.ModelState.TryAddModelError(path, formatterException, context.Metadata); return(InputFormatterResult.Failure()); } catch (Exception exception) when(exception is FormatException || exception is OverflowException) { context.ModelState.TryAddModelError(string.Empty, exception, context.Metadata); return(InputFormatterResult.Failure()); } finally { if (inputStream is TranscodingReadStream transcoding) { await transcoding.DisposeAsync(); } } if (model == null && !context.TreatEmptyInputAsDefaultValue) { return(InputFormatterResult.NoValue()); } else { return(InputFormatterResult.Success(model)); } }
public override async Task <InputFormatterResult> ReadRequestBodyAsync(InputFormatterContext context, Encoding encoding) { ArgumentNullException.ThrowIfNull(context); ArgumentNullException.ThrowIfNull(encoding); object?model; var httpContext = context.HttpContext; var registeredType = context.ModelType.GenericTypeArguments.FirstOrDefault(); if (registeredType == null || !_typeRepository.TryGet(registeredType, out var targetType)) { return(InputFormatterResult.Failure()); } var(inputStream, usesTranscodingStream) = GetInputStream(httpContext, encoding); try { model = await JsonSerializer.DeserializeAsync(inputStream, targetType, SerializerOptions); } catch (JsonException jsonException) { var path = jsonException.Path ?? string.Empty; var formatterException = new InputFormatterException(jsonException.Message, jsonException); context.ModelState.TryAddModelError(path, formatterException, context.Metadata); return(InputFormatterResult.Failure()); } finally { if (usesTranscodingStream) { await inputStream.DisposeAsync(); } } if (model == null && !context.TreatEmptyInputAsDefaultValue) { return(InputFormatterResult.NoValue()); } return(InputFormatterResult.Success(model)); }
public sealed override async Task <InputFormatterResult> ReadRequestBodyAsync( InputFormatterContext context, Encoding encoding) { if (context == null) { throw new ArgumentNullException(nameof(context)); } if (encoding == null) { throw new ArgumentNullException(nameof(encoding)); } if (encoding.CodePage != Encoding.UTF8.CodePage) { throw new NotSupportedException(encoding.EncodingName); } var httpContext = context.HttpContext; var inputStream = httpContext.Request.Body; if (context is FromBodyPropertyInputFormatterContext bodyPropertyContext) { Func <Func <Stream, JsonSerializerOptions, Task>, Task> readRequestBody = async(readAction) => { await readAction(inputStream, SerializerOptions); }; var result = await bodyPropertyContext.ReadAsync(readRequestBody, encoding); if (result.success) { if (result.noValue && !context.TreatEmptyInputAsDefaultValue) { // Some nonempty inputs might deserialize as null, for example whitespace, // or the JSON-encoded value "null". The upstream BodyModelBinder needs to // be notified that we don't regard this as a real input so it can register // a model binding error. return(InputFormatterResult.NoValue()); } Log.JsonInputSuccess(_logger, context.ModelType); return(InputFormatterResult.Success(result.model)); } else if (result.exception is JsonException jsonException) { var path = jsonException.Path; var formatterException = new InputFormatterException(jsonException.Message, jsonException); context.ModelState.TryAddModelError(path, formatterException, context.Metadata); Log.JsonInputException(_logger, jsonException); return(InputFormatterResult.Failure()); } else { var ex = result.exception ?? new Exception("Failed to read model"); throw ex; } } else { object model; try { model = await JsonSerializer.DeserializeAsync(inputStream, context.ModelType, SerializerOptions); } catch (JsonException jsonException) { var path = jsonException.Path; var formatterException = new InputFormatterException(jsonException.Message, jsonException); context.ModelState.TryAddModelError(path, formatterException, context.Metadata); Log.JsonInputException(_logger, jsonException); return(InputFormatterResult.Failure()); } if (model == null && !context.TreatEmptyInputAsDefaultValue) { // Some nonempty inputs might deserialize as null, for example whitespace, // or the JSON-encoded value "null". The upstream BodyModelBinder needs to // be notified that we don't regard this as a real input so it can register // a model binding error. return(InputFormatterResult.NoValue()); } else { Log.JsonInputSuccess(_logger, context.ModelType); return(InputFormatterResult.Success(model)); } } }
/// <inheritdoc /> public sealed override async Task <InputFormatterResult> ReadRequestBodyAsync( InputFormatterContext context, Encoding encoding) { if (context == null) { throw new ArgumentNullException(nameof(context)); } if (encoding == null) { throw new ArgumentNullException(nameof(encoding)); } var httpContext = context.HttpContext; var inputStream = httpContext.Request.Body; ApplicationPayload?model; try { using var inputStreamReader = new StreamReader(inputStream); var inputJsonString = await inputStreamReader.ReadToEndAsync(); // Determine options name to use (in case multiple are registered) var options = httpContext.Request.RouteValues.TryGetValue(RouteKeyConstants.OptionsName, out object optionsName) ? _options.Get(optionsName.ToString()) : _options.CurrentValue; // Verify signature if (options.ValidatePayloadSignature) { if (!string.IsNullOrEmpty(options.EndpointSigningKey)) { var secret = Encoding.ASCII.GetBytes(options.EndpointSigningKey); var signatureBytes = Encoding.UTF8.GetBytes(context.HttpContext.Request.Headers[HeaderSpaceTimestamp] + ":" + inputJsonString); using var hmSha1 = new HMACSHA256(secret); var signatureHash = hmSha1.ComputeHash(signatureBytes); var signatureString = ToHexString(signatureHash); if (!signatureString.Equals(context.HttpContext.Request.Headers[HeaderSpaceSignature])) { throw new InvalidOperationException("The webhook signature does not match the webhook payload. Make sure the endpoint signing key is configured correctly in your Space organization, and the current application."); } } else { _logger.LogWarning(nameof(SpaceWebHookOptions.ValidatePayloadSignature) + " is enabled, but no " + nameof(SpaceWebHookOptions.EndpointSigningKey) + " is configured. Skipping payload signature validation."); } } // Deserialize model model = JsonSerializer.Deserialize(inputJsonString, context.ModelType, _jsonSerializerOptions) as ApplicationPayload; if (model != null) { PropagatePropertyAccessPathHelper.SetAccessPathForValue(string.Empty, false, model); } // Verify payload if (options.ValidatePayloadVerificationToken) { var payloadVerificationTokenValue = GetPayloadVerificationTokenValue(model); if (!string.IsNullOrEmpty(payloadVerificationTokenValue)) { if (payloadVerificationTokenValue != options.EndpointVerificationToken) { throw new InvalidOperationException( "The webhook verification token does not your configured verification token. Make sure the endpoint verification token is configured correctly in your Space organization, and the current application."); } } else { _logger.LogWarning(nameof(SpaceWebHookOptions.ValidatePayloadVerificationToken) + " is enabled, but no " + nameof(SpaceWebHookOptions.EndpointVerificationToken) + " is configured. Skipping verification token validation."); } } } catch (JsonException jsonException) { var path = jsonException.Path; var formatterException = new InputFormatterException(jsonException.Message, jsonException); context.ModelState.TryAddModelError(path, formatterException, context.Metadata); Log.JsonInputException(_logger, jsonException); return(await InputFormatterResult.FailureAsync()); } catch (Exception exception) when(exception is FormatException || exception is OverflowException) { context.ModelState.TryAddModelError(string.Empty, exception, context.Metadata); Log.JsonInputException(_logger, exception); return(await InputFormatterResult.FailureAsync()); } if (model == null && !context.TreatEmptyInputAsDefaultValue) { return(await InputFormatterResult.NoValueAsync()); } Log.JsonInputSuccess(_logger, context.ModelType); return(await InputFormatterResult.SuccessAsync(model)); }