TcpRemoteForwarder: Parsing the MediaTypeHeaderValue correctly with TryParse and throwing if the parsing fails. (#92)

* Fix addresses issue #91

* added HTTP test

* config parser adjustment for the HTTP RemoteForward fix
This commit is contained in:
Clemens Vasters 2024-08-26 10:50:26 -07:00 коммит произвёл GitHub
Родитель 8e42cbbe6b
Коммит 631a3b1721
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: B5690EEEBB952194
4 изменённых файлов: 117 добавлений и 3 удалений

Просмотреть файл

@ -913,7 +913,9 @@ namespace Microsoft.Azure.Relay.Bridge.Configuration
RemoteForward remoteForward; RemoteForward remoteForward;
try try
{ {
remoteForward = new RemoteForward { RelayName = rf.Substring(0, firstColon), Http = true }; // we're not setting the Http flag here but only at the end of the method
// since we don't want a default binding to be created.
remoteForward = new RemoteForward { RelayName = rf.Substring(0, firstColon) };
} }
catch (ArgumentOutOfRangeException e) catch (ArgumentOutOfRangeException e)
{ {
@ -1028,6 +1030,7 @@ namespace Microsoft.Azure.Relay.Bridge.Configuration
} }
} }
} }
remoteForward.Http = true;
} }
private static void CheckHttpPortName(Config config, string rf, string portName) private static void CheckHttpPortName(Config config, string rf, string portName)

Просмотреть файл

@ -148,7 +148,28 @@ namespace Microsoft.Azure.Relay.Bridge.Configuration
public bool Http public bool Http
{ {
get; set; get
{
if (bindings.Count == 1)
{
return bindings[0].Http;
}
else
{
return false;
}
}
set
{
if (bindings.Count == 0)
{
bindings.Add(new RemoteForwardBinding { Http = value });
}
else
{
bindings[0].Http = value;
}
}
} }

Просмотреть файл

@ -138,7 +138,14 @@ namespace Microsoft.Azure.Relay.Bridge
string contentType = context.Request.Headers[HttpRequestHeader.ContentType]; string contentType = context.Request.Headers[HttpRequestHeader.ContentType];
if (!string.IsNullOrEmpty(contentType)) if (!string.IsNullOrEmpty(contentType))
{ {
requestMessage.Content.Headers.ContentType = new MediaTypeHeaderValue(contentType); if (MediaTypeHeaderValue.TryParse(contentType, out var mediaTypeHeaderValue))
{
requestMessage.Content.Headers.ContentType = mediaTypeHeaderValue;
}
else
{
throw new InvalidOperationException($"Invalid Content-Type header value: {contentType}");
}
} }
} }

Просмотреть файл

@ -6,7 +6,10 @@ namespace Microsoft.Azure.Relay.Bridge.Test
using System; using System;
using System.IO; using System.IO;
using System.Net; using System.Net;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Net.Sockets; using System.Net.Sockets;
using System.Threading.Tasks;
using Microsoft.Azure.Relay.Bridge.Configuration; using Microsoft.Azure.Relay.Bridge.Configuration;
using Microsoft.Azure.Relay.Bridge.Tests; using Microsoft.Azure.Relay.Bridge.Tests;
using Xunit; using Xunit;
@ -291,5 +294,85 @@ namespace Microsoft.Azure.Relay.Bridge.Test
host.Stop(); host.Stop();
} }
} }
[Fact]
public void HttpBridge()
{
// set up the bridge first
Config cfg = new Config
{
AzureRelayConnectionString = Utilities.GetConnectionString()
};
cfg.RemoteForward.Add(new RemoteForward
{
Host = "127.0.97.2",
HostPort = 29877,
PortName = "http",
RelayName = "http",
Http = true
});
Host host = new Host(cfg);
host.Start();
try
{
RelayConnectionStringBuilder csb = new RelayConnectionStringBuilder(Utilities.GetConnectionString());
var httpEndpoint = new UriBuilder(csb.Endpoint) { Scheme = "https", Port = 443, Path="http" }.Uri;
var httpSasToken = TokenProvider.CreateSharedAccessSignatureTokenProvider(csb.SharedAccessKeyName, csb.SharedAccessKey).GetTokenAsync(httpEndpoint.AbsoluteUri, TimeSpan.FromHours(1)).Result.TokenString;
using (var l = new HttpListener())
{
l.Prefixes.Add("http://127.0.97.2:29877/");
l.Start();
var handler = (Task<HttpListenerContext> t) =>
{
var c = t.Result;
using (var b = new StreamReader(c.Request.InputStream))
{
var text = b.ReadLine();
using (var w = new StreamWriter(c.Response.OutputStream))
{
w.WriteLine(text);
w.Flush();
}
c.Response.Close();
}
};
var testMessage = "Hello!";
using (var c = new HttpClient())
{
c.DefaultRequestHeaders.Add("Authorization", httpSasToken);
// listen for exactly one request
l.GetContextAsync().ContinueWith(handler);
var r = c.PostAsync(httpEndpoint, new StringContent(testMessage)).GetAwaiter().GetResult();
Assert.True(r.IsSuccessStatusCode);
var result = r.Content.ReadAsStringAsync().GetAwaiter().GetResult();
Assert.Equal(testMessage, result.Trim());
r.Dispose();
// listen for exactly one request
l.GetContextAsync().ContinueWith(handler);
var mtv = MediaTypeHeaderValue.Parse("application/cloudevents+json;charset=utf-8;foo=bar");
var r2 = c.PostAsync(httpEndpoint, new StringContent(testMessage, mtv)).GetAwaiter().GetResult();
Assert.True(r2.IsSuccessStatusCode);
var result2 = r2.Content.ReadAsStringAsync().GetAwaiter().GetResult();
Assert.Equal(testMessage, result2.Trim());
r2.Dispose();
}
}
}
finally
{
host.Stop();
}
}
} }
} }