@@ -167,24 +167,46 @@ public class ApiClient : IDisposable {
167167 }
168168
169169 /// <summary >
170- /// Builds the complete headers dictionary by merging OAuth token and per-request headers
170+ /// Builds the complete headers dictionary by merging OAuth token and per-request headers.
171+ /// Validates per-request headers and performs case-insensitive merging.
171172 /// </summary >
172173 /// <param name =" oauthToken" >OAuth access token if available</param >
173174 /// <param name =" perRequestHeaders" >Per-request custom headers</param >
174175 /// <returns >Merged headers dictionary or null if no headers to add</returns >
176+ /// <exception cref =" ArgumentException" >Thrown when header key is null, empty, or whitespace</exception >
177+ /// <exception cref =" ArgumentNullException" >Thrown when header value is null</exception >
175178 private static IDictionary<string , string >? BuildHeaders(string? oauthToken, IDictionary<string , string >? perRequestHeaders) {
176- if (string.IsNullOrEmpty(oauthToken) && perRequestHeaders == null) {
179+ // Validate per-request headers at the client boundary
180+ if (perRequestHeaders != null) {
181+ foreach (var header in perRequestHeaders) {
182+ if (string.IsNullOrWhiteSpace(header.Key)) {
183+ throw new ArgumentException(
184+ " Header name cannot be null, empty, or whitespace." ,
185+ nameof(perRequestHeaders));
186+ }
187+
188+ if (header.Value == null) {
189+ throw new ArgumentNullException(
190+ nameof(perRequestHeaders),
191+ $" Header '{header.Key}' has a null value. Header values cannot be null." );
192+ }
193+ }
194+ }
195+
196+ // Return null if no headers to add
197+ if (string.IsNullOrEmpty(oauthToken) && (perRequestHeaders == null || perRequestHeaders.Count == 0)) {
177198 return null;
178199 }
179200
180- var headers = new Dictionary<string , string >();
201+ // Use case-insensitive dictionary for proper header merging
202+ var headers = new Dictionary<string , string >(StringComparer.OrdinalIgnoreCase);
181203
182- // Add OAuth token header if present
204+ // Add OAuth token header first
183205 if (!string.IsNullOrEmpty(oauthToken)) {
184206 headers[" Authorization" ] = $" Bearer {oauthToken}" ;
185207 }
186208
187- // Merge per-request headers (these take precedence)
209+ // Overlay per-request headers (these take precedence regardless of casing )
188210 if (perRequestHeaders != null) {
189211 foreach (var header in perRequestHeaders) {
190212 headers[header.Key] = header.Value;
0 commit comments