Skip to content

Add Feature Extension for User Agent #3451

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

Merged
merged 8 commits into from
Jul 8, 2025
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -207,6 +207,9 @@ internal bool IsDNSCachingBeforeRedirectSupported
// Json Support Flag
internal bool IsJsonSupportEnabled = false;

// User Agent Flag
internal bool IsUserAgentEnabled = true;

// Vector Support Flag
internal bool IsVectorSupportEnabled = false;

Expand Down Expand Up @@ -1430,6 +1433,10 @@ private void Login(ServerInfo server, TimeoutTimer timeout, string newPassword,
requestedFeatures |= TdsEnums.FeatureExtension.JsonSupport;
requestedFeatures |= TdsEnums.FeatureExtension.VectorSupport;

#if DEBUG
requestedFeatures |= TdsEnums.FeatureExtension.UserAgent;
#endif

_parser.TdsLogin(login, requestedFeatures, _recoverySessionData, _fedAuthFeatureExtensionData, encrypt);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8579,6 +8579,49 @@ internal int WriteVectorSupportFeatureRequest(bool write)
return len;
}

/// <summary>
/// Writes the User Agent feature request to the physical state object.
/// The request includes the feature ID, feature data length, version number and encoded JSON payload.
/// </summary>
/// <param name="userAgentJsonPayload"> Byte array of UTF-8 encoded JSON payload for User Agent</param>
/// <param name="write">
/// If true, writes the feature request to the physical state object.
/// If false, just calculates the length.
/// </param>
/// <returns>The length of the feature request in bytes.</returns>
/// <remarks>
/// The feature request consists of:
/// - 1 byte for the feature ID.
/// - 4 bytes for the feature data length.
/// - 1 byte for the version number.
/// - N bytes for the JSON payload
/// </remarks>
internal int WriteUserAgentFeatureRequest(byte[] userAgentJsonPayload,
bool write)
{
// 1byte (Feature Version) + size of UTF-8 encoded JSON payload
int dataLen = 1 + userAgentJsonPayload.Length;
// 1byte (Feature ID) + 4bytes (Feature Data Length) + 1byte (Version) + N(JSON payload size)
int totalLen = 1 + 4 + dataLen;

if (write)
{
// Write Feature ID
_physicalStateObj.WriteByte(TdsEnums.FEATUREEXT_USERAGENT);

// Feature Data Length
WriteInt(dataLen, _physicalStateObj);

// Write Feature Version
_physicalStateObj.WriteByte(TdsEnums.SUPPORTED_USER_AGENT_VERSION);

// Write encoded JSON payload
_physicalStateObj.WriteByteArray(userAgentJsonPayload, userAgentJsonPayload.Length, 0);
}

return totalLen;
}

private void WriteLoginData(SqlLogin rec,
TdsEnums.FeatureExtension requestedFeatures,
SessionData recoverySessionData,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -211,6 +211,9 @@ internal bool IsDNSCachingBeforeRedirectSupported
// Vector Support Flag
internal bool IsVectorSupportEnabled = false;

// User Agent Flag
internal bool IsUserAgentEnabled = true;

// TCE flags
internal byte _tceVersionSupported;

Expand Down Expand Up @@ -1436,6 +1439,10 @@ private void Login(ServerInfo server, TimeoutTimer timeout, string newPassword,
requestedFeatures |= TdsEnums.FeatureExtension.JsonSupport;
requestedFeatures |= TdsEnums.FeatureExtension.VectorSupport;

#if DEBUG
requestedFeatures |= TdsEnums.FeatureExtension.UserAgent;
#endif

_parser.TdsLogin(login, requestedFeatures, _recoverySessionData, _fedAuthFeatureExtensionData, encrypt);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8762,6 +8762,49 @@ internal int WriteVectorSupportFeatureRequest(bool write)
return len;
}

/// <summary>
/// Writes the User Agent feature request to the physical state object.
/// The request includes the feature ID, feature data length, version number and encoded JSON payload.
/// </summary>
/// <param name="userAgentJsonPayload"> Byte array of UTF-8 encoded JSON payload for User Agent</param>
/// <param name="write">
/// If true, writes the feature request to the physical state object.
/// If false, just calculates the length.
/// </param>
/// <returns>The length of the feature request in bytes.</returns>
/// <remarks>
/// The feature request consists of:
/// - 1 byte for the feature ID.
/// - 4 bytes for the feature data length.
/// - 1 byte for the version number.
/// - N bytes for the JSON payload
/// </remarks>
internal int WriteUserAgentFeatureRequest(byte[] userAgentJsonPayload,
bool write)
{
// 1byte (Feature Version) + size of UTF-8 encoded JSON payload
int dataLen = 1 + userAgentJsonPayload.Length;
// 1byte (Feature ID) + 4bytes (Feature Data Length) + 1byte (Version) + N(JSON payload size)
int totalLen = 1 + 4 + dataLen;

if (write)
{
// Write Feature ID
_physicalStateObj.WriteByte(TdsEnums.FEATUREEXT_USERAGENT);

// Feature Data Length
WriteInt(dataLen, _physicalStateObj);

// Write Feature Version
_physicalStateObj.WriteByte(TdsEnums.SUPPORTED_USER_AGENT_VERSION);

// Write encoded JSON payload
_physicalStateObj.WriteByteArray(userAgentJsonPayload, userAgentJsonPayload.Length, 0);
}

return totalLen;
}

private void WriteLoginData(SqlLogin rec,
TdsEnums.FeatureExtension requestedFeatures,
SessionData recoverySessionData,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -241,6 +241,8 @@ public enum EnvChangeType : byte
public const byte FEATUREEXT_SQLDNSCACHING = 0x0B;
public const byte FEATUREEXT_JSONSUPPORT = 0x0D;
public const byte FEATUREEXT_VECTORSUPPORT = 0x0E;
// TODO: re-verify if this byte competes with another feature
public const byte FEATUREEXT_USERAGENT = 0x0F;

[Flags]
public enum FeatureExtension : uint
Expand All @@ -255,7 +257,8 @@ public enum FeatureExtension : uint
UTF8Support = 1 << (TdsEnums.FEATUREEXT_UTF8SUPPORT - 1),
SQLDNSCaching = 1 << (TdsEnums.FEATUREEXT_SQLDNSCACHING - 1),
JsonSupport = 1 << (TdsEnums.FEATUREEXT_JSONSUPPORT - 1),
VectorSupport = 1 << (TdsEnums.FEATUREEXT_VECTORSUPPORT - 1)
VectorSupport = 1 << (TdsEnums.FEATUREEXT_VECTORSUPPORT - 1),
UserAgent = 1 << (TdsEnums.FEATUREEXT_USERAGENT - 1)
}

public const uint UTF8_IN_TDSCOLLATION = 0x4000000;
Expand Down Expand Up @@ -985,6 +988,9 @@ internal enum FedAuthInfoId : byte
internal const byte MAX_SUPPORTED_VECTOR_VERSION = 0x01;
internal const int VECTOR_HEADER_SIZE = 8;

// User Agent constants
internal const byte SUPPORTED_USER_AGENT_VERSION = 0x01;

// TCE Related constants
internal const byte MAX_SUPPORTED_TCE_VERSION = 0x03; // max version
internal const byte MIN_TCE_VERSION_WITH_ENCLAVE_SUPPORT = 0x02; // min version with enclave support
Expand Down
Loading