Skip to content

Commit e0fb2e4

Browse files
committed
add headers order (android only)
1 parent f5c9a51 commit e0fb2e4

6 files changed

Lines changed: 124 additions & 1 deletion

File tree

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
## 2.1.2
22
- vs : 17.5.4 (maui 7.0.81 ; android 33.0.46 ; ios 16.2.2035)
33
- dotnet sdk 7.0.203
4+
- add headers order (android only)
45

56
## 2.1.1
67
- vs : 17.5.0 (maui 7.0.59 ; android 33.0.26 ; ios 16.2.1024)
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
package securehttpclient.okhttp;
2+
3+
import java.io.IOException;
4+
5+
import okhttp3.Headers;
6+
import okhttp3.Interceptor;
7+
import okhttp3.Request;
8+
import okhttp3.Response;
9+
10+
public class HeadersOrderInterceptor implements Interceptor {
11+
12+
private static final String HEADERS_ORDER_HEADER = "securehttpclient-headers-order";
13+
14+
@Override
15+
public Response intercept(Chain chain) throws IOException {
16+
Request original = chain.request();
17+
18+
if (original.header(HEADERS_ORDER_HEADER) == null) {
19+
return chain.proceed(original);
20+
}
21+
22+
Request.Builder requestBuilder = original.newBuilder();
23+
24+
String headersOrderHeader = original.header(HEADERS_ORDER_HEADER);
25+
String[] headersOrderArray = headersOrderHeader.split(";");
26+
27+
for (String name : headersOrderArray) {
28+
if (original.header(name) != null) {
29+
String header = original.header(name);
30+
requestBuilder
31+
.removeHeader(name)
32+
.addHeader(name, header);
33+
}
34+
}
35+
36+
Request request = requestBuilder
37+
.removeHeader(HEADERS_ORDER_HEADER)
38+
.build();
39+
40+
return chain.proceed(request);
41+
}
42+
}

SecureHttpClient.Test/HttpTest.cs

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
using System.Text.Json;
77
using System.Threading.Tasks;
88
using Microsoft.Maui.Devices;
9+
using SecureHttpClient.Extensions;
910
using SecureHttpClient.Test.Helpers;
1011
using Xunit;
1112

@@ -49,6 +50,45 @@ public async Task HttpTest_Gzip_WithRequestHeader()
4950
Assert.True(url);
5051
}
5152

53+
[Fact]
54+
public async Task HttpTest_Headers()
55+
{
56+
const string page = @"https://postman-echo.com/get";
57+
var req = new HttpRequestMessage(HttpMethod.Get, page);
58+
req.Headers.Add("header1", "value1");
59+
req.Headers.Add("header2", "value2");
60+
req.Headers.Add("header3", "value3");
61+
var result = await SendAsync(req).ReceiveString();
62+
var json = JsonDocument.Parse(result);
63+
var headers = json.RootElement.GetProperty("headers").Deserialize<Dictionary<string, string>>().Select(kv => kv.Key).ToList();
64+
var index1 = headers.IndexOf("header1");
65+
var index2 = headers.IndexOf("header2");
66+
var index3 = headers.IndexOf("header3");
67+
Assert.Equal(1, index2 - index1);
68+
Assert.Equal(1, index3 - index2);
69+
}
70+
71+
[SkippableFact]
72+
public async Task HttpTest_HeadersOrder()
73+
{
74+
Skip.If(DeviceInfo.Platform != DevicePlatform.Android, "Only on Android");
75+
76+
const string page = @"https://postman-echo.com/get";
77+
var req = new HttpRequestMessage(HttpMethod.Get, page);
78+
req.Headers.Add("header1", "value1");
79+
req.Headers.Add("header2", "value2");
80+
req.Headers.Add("header3", "value3");
81+
req.SetHeadersOrder("header3", "header2", "header1");
82+
var result = await SendAsync(req).ReceiveString();
83+
var json = JsonDocument.Parse(result);
84+
var headers = json.RootElement.GetProperty("headers").Deserialize<Dictionary<string, string>>().Select(kv => kv.Key).ToList();
85+
var index1 = headers.IndexOf("header1");
86+
var index2 = headers.IndexOf("header2");
87+
var index3 = headers.IndexOf("header3");
88+
Assert.Equal(1, index2 - index3);
89+
Assert.Equal(1, index1 - index2);
90+
}
91+
5292
[SkippableFact]
5393
public async Task HttpTest_Deflate()
5494
{
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
using System.Net.Http;
2+
3+
namespace SecureHttpClient.Extensions
4+
{
5+
/// <summary>
6+
/// Request properties extensions
7+
/// </summary>
8+
public static class RequestPropertiesExtensions
9+
{
10+
private const string HeadersOrderPropertyKey = "headersOrder";
11+
12+
/// <summary>
13+
/// Set the headers order
14+
/// </summary>
15+
/// <param name="request">The request</param>
16+
/// <param name="headers">The ordered headers names</param>
17+
public static void SetHeadersOrder(this HttpRequestMessage request, params string[] headers)
18+
{
19+
request.Options.Set(new HttpRequestOptionsKey<object>(HeadersOrderPropertyKey), headers);
20+
}
21+
22+
internal static string[] GetHeadersOrder(this HttpRequestMessage request)
23+
{
24+
if (request.Options.TryGetValue(new HttpRequestOptionsKey<object>(HeadersOrderPropertyKey), out var value))
25+
{
26+
return (string[])value;
27+
}
28+
return null;
29+
}
30+
}
31+
}

SecureHttpClient/Platforms/Android/SecureHttpClientHandler.cs

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
using Microsoft.Extensions.Logging;
1818
using System.Security.Authentication;
1919
using Java.Net;
20+
using SecureHttpClient.Extensions;
2021

2122
namespace SecureHttpClient
2223
{
@@ -113,7 +114,8 @@ private OkHttpClient CreateOkHttpClientInstance()
113114
.WriteTimeout(100, TimeUnit.Seconds)
114115
.ReadTimeout(100, TimeUnit.Seconds)
115116
.FollowRedirects(AllowAutoRedirect)
116-
.AddInterceptor(new DecompressInterceptor());
117+
.AddInterceptor(new DecompressInterceptor())
118+
.AddNetworkInterceptor(new HeadersOrderInterceptor());
117119

118120
if (UseCookies)
119121
{
@@ -181,6 +183,12 @@ protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage
181183
builder.AddHeader(name, string.Join(headerSeparator, values));
182184
}
183185

186+
var headersOrder = request.GetHeadersOrder();
187+
if (headersOrder != null)
188+
{
189+
builder.AddHeader("securehttpclient-headers-order", string.Join(';', headersOrder));
190+
}
191+
184192
cancellationToken.ThrowIfCancellationRequested();
185193

186194
var rq = builder.Build();

SecureHttpClient/SecureHttpClient.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313

1414
<ItemGroup>
1515
<None Include="**\*.cs;**\*.xml;**\*.axml;**\*.png" Exclude="obj\**\*.*;bin\**\*.*;bin;obj" />
16+
<Compile Include="Extensions\**\*.cs" />
1617
<Compile Include="Abstractions\**\*.cs" />
1718
<Compile Include="CertificatePinning\**\*.cs" />
1819
</ItemGroup>

0 commit comments

Comments
 (0)