-
Notifications
You must be signed in to change notification settings - Fork 299
Add HTTP Response Compression Support #3003
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from 3 commits
5aa5ce7
5e5a865
1a8cd13
c53261c
6326ead
a832d08
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
|
|
@@ -828,6 +828,21 @@ private static bool TryUpdateConfiguredRuntimeOptions( | |||||
| } | ||||||
| } | ||||||
|
|
||||||
| // Compression: Level | ||||||
| if (options.RuntimeCompressionLevel != null) | ||||||
| { | ||||||
| CompressionOptions updatedCompressionOptions = runtimeConfig?.Runtime?.Compression ?? new(); | ||||||
| bool status = TryUpdateConfiguredCompressionValues(options, ref updatedCompressionOptions); | ||||||
| if (status) | ||||||
| { | ||||||
| runtimeConfig = runtimeConfig! with { Runtime = runtimeConfig.Runtime! with { Compression = updatedCompressionOptions } }; | ||||||
| } | ||||||
| else | ||||||
| { | ||||||
| return false; | ||||||
| } | ||||||
| } | ||||||
|
|
||||||
| // Host: Mode, Cors.Origins, Cors.AllowCredentials, Authentication.Provider, Authentication.Jwt.Audience, Authentication.Jwt.Issuer | ||||||
| if (options.RuntimeHostMode != null || | ||||||
| options.RuntimeHostCorsOrigins != null || | ||||||
|
|
@@ -1197,6 +1212,37 @@ private static bool TryUpdateConfiguredCacheValues( | |||||
| } | ||||||
| } | ||||||
|
|
||||||
| /// <summary> | ||||||
| /// Attempts to update the Config parameters in the Compression runtime settings based on the provided value. | ||||||
| /// Validates user-provided parameters and then returns true if the updated Compression options | ||||||
| /// need to be overwritten on the existing config parameters. | ||||||
| /// </summary> | ||||||
| /// <param name="options">options.</param> | ||||||
| /// <param name="updatedCompressionOptions">updatedCompressionOptions.</param> | ||||||
| /// <returns>True if the value needs to be updated in the runtime config, else false</returns> | ||||||
| private static bool TryUpdateConfiguredCompressionValues( | ||||||
| ConfigureOptions options, | ||||||
| ref CompressionOptions updatedCompressionOptions) | ||||||
| { | ||||||
| try | ||||||
| { | ||||||
| // Runtime.Compression.Level | ||||||
| CompressionLevel? updatedValue = options?.RuntimeCompressionLevel; | ||||||
| if (updatedValue != null) | ||||||
| { | ||||||
| updatedCompressionOptions = updatedCompressionOptions with { Level = updatedValue.Value, UserProvidedLevel = true }; | ||||||
| _logger.LogInformation("Updated RuntimeConfig with Runtime.Compression.Level as '{updatedValue}'", updatedValue); | ||||||
| } | ||||||
|
|
||||||
| return true; | ||||||
| } | ||||||
| catch (Exception ex) | ||||||
| { | ||||||
| _logger.LogError("Failed to update RuntimeConfig.Compression with exception message: {exceptionMessage}.", ex.Message); | ||||||
|
||||||
| _logger.LogError("Failed to update RuntimeConfig.Compression with exception message: {exceptionMessage}.", ex.Message); | |
| _logger.LogError("Failed to configure RuntimeConfig.Compression with exception message: {exceptionMessage}.", ex.Message); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Updated error message to use "configure" instead of "update" for consistency. Fixed in commit c53261c.
| Original file line number | Diff line number | Diff line change | ||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,99 @@ | ||||||||||||||
| // Copyright (c) Microsoft Corporation. | ||||||||||||||
| // Licensed under the MIT License. | ||||||||||||||
|
|
||||||||||||||
| using System.Text.Json; | ||||||||||||||
| using System.Text.Json.Serialization; | ||||||||||||||
| using Azure.DataApiBuilder.Config.ObjectModel; | ||||||||||||||
|
|
||||||||||||||
| namespace Azure.DataApiBuilder.Config.Converters; | ||||||||||||||
|
|
||||||||||||||
| /// <summary> | ||||||||||||||
| /// Defines how DAB reads and writes the compression options (JSON). | ||||||||||||||
| /// </summary> | ||||||||||||||
| internal class CompressionOptionsConverterFactory : JsonConverterFactory | ||||||||||||||
| { | ||||||||||||||
| /// <inheritdoc/> | ||||||||||||||
| public override bool CanConvert(Type typeToConvert) | ||||||||||||||
| { | ||||||||||||||
| return typeToConvert.IsAssignableTo(typeof(CompressionOptions)); | ||||||||||||||
| } | ||||||||||||||
|
|
||||||||||||||
| /// <inheritdoc/> | ||||||||||||||
| public override JsonConverter? CreateConverter(Type typeToConvert, JsonSerializerOptions options) | ||||||||||||||
| { | ||||||||||||||
| return new CompressionOptionsConverter(); | ||||||||||||||
| } | ||||||||||||||
|
|
||||||||||||||
| private class CompressionOptionsConverter : JsonConverter<CompressionOptions> | ||||||||||||||
| { | ||||||||||||||
| /// <summary> | ||||||||||||||
| /// Defines how DAB reads the compression options and defines which values are | ||||||||||||||
| /// used to instantiate CompressionOptions. | ||||||||||||||
| /// </summary> | ||||||||||||||
| public override CompressionOptions? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) | ||||||||||||||
| { | ||||||||||||||
| if (reader.TokenType == JsonTokenType.Null) | ||||||||||||||
| { | ||||||||||||||
| return null; | ||||||||||||||
| } | ||||||||||||||
|
|
||||||||||||||
| if (reader.TokenType != JsonTokenType.StartObject) | ||||||||||||||
| { | ||||||||||||||
| throw new JsonException("Expected start of object."); | ||||||||||||||
| } | ||||||||||||||
|
|
||||||||||||||
| CompressionLevel level = CompressionOptions.DEFAULT_LEVEL; | ||||||||||||||
| bool userProvidedLevel = false; | ||||||||||||||
|
|
||||||||||||||
| while (reader.Read()) | ||||||||||||||
| { | ||||||||||||||
| if (reader.TokenType == JsonTokenType.EndObject) | ||||||||||||||
| { | ||||||||||||||
| break; | ||||||||||||||
| } | ||||||||||||||
|
|
||||||||||||||
| if (reader.TokenType == JsonTokenType.PropertyName) | ||||||||||||||
| { | ||||||||||||||
| string? propertyName = reader.GetString(); | ||||||||||||||
| reader.Read(); | ||||||||||||||
|
|
||||||||||||||
| if (string.Equals(propertyName, "level", StringComparison.OrdinalIgnoreCase)) | ||||||||||||||
| { | ||||||||||||||
| string? levelStr = reader.GetString(); | ||||||||||||||
| if (levelStr is not null) | ||||||||||||||
| { | ||||||||||||||
| if (Enum.TryParse<CompressionLevel>(levelStr, ignoreCase: true, out CompressionLevel parsedLevel)) | ||||||||||||||
| { | ||||||||||||||
| level = parsedLevel; | ||||||||||||||
| userProvidedLevel = true; | ||||||||||||||
| } | ||||||||||||||
| else | ||||||||||||||
| { | ||||||||||||||
| throw new JsonException($"Invalid compression level: '{levelStr}'. Valid values are: optimal, fastest, none."); | ||||||||||||||
| } | ||||||||||||||
| } | ||||||||||||||
| } | ||||||||||||||
| } | ||||||||||||||
|
||||||||||||||
| } | |
| else | |
| { | |
| // Skip unknown properties and their values (including objects/arrays) | |
| reader.Skip(); | |
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Added the else block to properly skip unknown properties including objects and arrays using reader.Skip(). Fixed in commit c53261c.
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,28 @@ | ||
| // Copyright (c) Microsoft Corporation. | ||
| // Licensed under the MIT License. | ||
|
|
||
| using System.Text.Json.Serialization; | ||
|
|
||
| namespace Azure.DataApiBuilder.Config.ObjectModel; | ||
|
|
||
| /// <summary> | ||
| /// Specifies the compression level for HTTP response compression. | ||
| /// </summary> | ||
| [JsonConverter(typeof(JsonStringEnumConverter))] | ||
| public enum CompressionLevel | ||
| { | ||
| /// <summary> | ||
| /// Provides the best compression ratio at the cost of speed. | ||
| /// </summary> | ||
| Optimal, | ||
|
|
||
| /// <summary> | ||
| /// Provides the fastest compression at the cost of compression ratio. | ||
| /// </summary> | ||
| Fastest, | ||
|
|
||
| /// <summary> | ||
| /// Disables compression. | ||
| /// </summary> | ||
| None | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,46 @@ | ||
| // Copyright (c) Microsoft Corporation. | ||
| // Licensed under the MIT License. | ||
|
|
||
| using System.Text.Json.Serialization; | ||
|
|
||
| namespace Azure.DataApiBuilder.Config.ObjectModel; | ||
|
|
||
| /// <summary> | ||
| /// Configuration options for HTTP response compression. | ||
| /// </summary> | ||
| public record CompressionOptions | ||
| { | ||
| /// <summary> | ||
| /// Default compression level is Optimal. | ||
| /// </summary> | ||
| public const CompressionLevel DEFAULT_LEVEL = CompressionLevel.Optimal; | ||
|
|
||
| /// <summary> | ||
| /// The compression level to use for HTTP response compression. | ||
| /// </summary> | ||
| [JsonPropertyName("level")] | ||
| public CompressionLevel Level { get; init; } = DEFAULT_LEVEL; | ||
|
|
||
| /// <summary> | ||
| /// Flag which informs CLI and JSON serializer whether to write Level | ||
| /// property and value to the runtime config file. | ||
| /// </summary> | ||
| [JsonIgnore(Condition = JsonIgnoreCondition.Always)] | ||
| public bool UserProvidedLevel { get; init; } = false; | ||
|
|
||
| [JsonConstructor] | ||
| public CompressionOptions(CompressionLevel Level = DEFAULT_LEVEL) | ||
| { | ||
| this.Level = Level; | ||
| this.UserProvidedLevel = true; | ||
| } | ||
|
|
||
| /// <summary> | ||
| /// Default parameterless constructor for cases where no compression level is specified. | ||
| /// </summary> | ||
| public CompressionOptions() | ||
| { | ||
| this.Level = DEFAULT_LEVEL; | ||
| this.UserProvidedLevel = false; | ||
| } | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Missing closing period in the documentation comment. The summary should end with a period for consistency with other test documentation in the file.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Added the missing period to the documentation comment. Fixed in commit c53261c.