parent
fd7707e7d2
commit
e691e1cff8
|
|
@ -1,24 +1,25 @@
|
||||||
export interface IHttpClient {
|
export interface IHttpClient {
|
||||||
get(url: string): Promise<string>;
|
get(url: string, headers?: Map<string, string>): Promise<string>;
|
||||||
post(url: string, content: string): Promise<string>;
|
post(url: string, content: string, headers?: Map<string, string>): Promise<string>;
|
||||||
}
|
}
|
||||||
|
|
||||||
export class HttpClient implements IHttpClient {
|
export class HttpClient implements IHttpClient {
|
||||||
get(url: string): Promise<string> {
|
get(url: string, headers?: Map<string, string>): Promise<string> {
|
||||||
return this.xhr("GET", url);
|
return this.xhr("GET", url, headers);
|
||||||
}
|
}
|
||||||
|
|
||||||
post(url: string, content: string): Promise<string> {
|
post(url: string, content: string, headers?: Map<string, string>): Promise<string> {
|
||||||
return this.xhr("POST", url, content);
|
return this.xhr("POST", url, headers, content);
|
||||||
}
|
}
|
||||||
|
|
||||||
private xhr(method: string, url: string, content?: string): Promise<string> {
|
private xhr(method: string, url: string, headers?: Map<string, string>, content?: string): Promise<string> {
|
||||||
return new Promise<string>((resolve, reject) => {
|
return new Promise<string>((resolve, reject) => {
|
||||||
let xhr = new XMLHttpRequest();
|
let xhr = new XMLHttpRequest();
|
||||||
|
|
||||||
xhr.open(method, url, true);
|
xhr.open(method, url, true);
|
||||||
|
|
||||||
if (method === "POST" && content != null) {
|
if (headers) {
|
||||||
xhr.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
|
headers.forEach((value, header) => xhr.setRequestHeader(header, value));
|
||||||
}
|
}
|
||||||
|
|
||||||
xhr.send(content);
|
xhr.send(content);
|
||||||
|
|
|
||||||
|
|
@ -139,7 +139,7 @@ export class ServerSentEventsTransport implements ITransport {
|
||||||
}
|
}
|
||||||
|
|
||||||
async send(data: any): Promise<void> {
|
async send(data: any): Promise<void> {
|
||||||
await this.httpClient.post(this.url + "/send?" + this.queryString, data);
|
return send(this.httpClient, `${this.url}/send?${this.queryString}`, data);
|
||||||
}
|
}
|
||||||
|
|
||||||
stop(): void {
|
stop(): void {
|
||||||
|
|
@ -231,7 +231,7 @@ export class LongPollingTransport implements ITransport {
|
||||||
}
|
}
|
||||||
|
|
||||||
async send(data: any): Promise<void> {
|
async send(data: any): Promise<void> {
|
||||||
await this.httpClient.post(this.url + "/send?" + this.queryString, data);
|
return send(this.httpClient, `${this.url}/send?${this.queryString}`, data);
|
||||||
}
|
}
|
||||||
|
|
||||||
stop(): void {
|
stop(): void {
|
||||||
|
|
@ -245,3 +245,11 @@ export class LongPollingTransport implements ITransport {
|
||||||
onDataReceived: DataReceived;
|
onDataReceived: DataReceived;
|
||||||
onClosed: TransportClosed;
|
onClosed: TransportClosed;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const headers = new Map<string, string>();
|
||||||
|
headers.set("Content-Type", "application/vnd.microsoft.aspnetcore.endpoint-messages.v1+text");
|
||||||
|
|
||||||
|
async function send(httpClient: IHttpClient, url: string, data: any): Promise<void> {
|
||||||
|
let message = `T${data.length.toString()}:T:${data};`;
|
||||||
|
await httpClient.post(url, message, headers);
|
||||||
|
}
|
||||||
|
|
@ -338,31 +338,24 @@ namespace Microsoft.AspNetCore.Sockets
|
||||||
buffer = stream.ToArray();
|
buffer = stream.ToArray();
|
||||||
}
|
}
|
||||||
|
|
||||||
IList<Message> messages;
|
MessageFormat messageFormat;
|
||||||
if (string.Equals(context.Request.ContentType, MessageFormatter.TextContentType, StringComparison.OrdinalIgnoreCase))
|
if (string.Equals(context.Request.ContentType, MessageFormatter.TextContentType, StringComparison.OrdinalIgnoreCase))
|
||||||
{
|
{
|
||||||
var reader = new BytesReader(buffer);
|
messageFormat = MessageFormat.Text;
|
||||||
messages = ParseSendBatch(ref reader, MessageFormat.Text);
|
|
||||||
}
|
}
|
||||||
else if (string.Equals(context.Request.ContentType, MessageFormatter.BinaryContentType, StringComparison.OrdinalIgnoreCase))
|
else if (string.Equals(context.Request.ContentType, MessageFormatter.BinaryContentType, StringComparison.OrdinalIgnoreCase))
|
||||||
{
|
{
|
||||||
var reader = new BytesReader(buffer);
|
messageFormat = MessageFormat.Binary;
|
||||||
messages = ParseSendBatch(ref reader, MessageFormat.Binary);
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// Legacy, single message raw format
|
context.Response.StatusCode = StatusCodes.Status400BadRequest;
|
||||||
|
await context.Response.WriteAsync($"'{context.Request.ContentType}' is not a valid Content-Type for send requests.");
|
||||||
var format =
|
return;
|
||||||
string.Equals(context.Request.Query["format"], "binary", StringComparison.OrdinalIgnoreCase)
|
|
||||||
? MessageType.Binary
|
|
||||||
: MessageType.Text;
|
|
||||||
messages = new List<Message>()
|
|
||||||
{
|
|
||||||
new Message(buffer, format, endOfMessage: true)
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var reader = new BytesReader(buffer);
|
||||||
|
var messages = ParseSendBatch(ref reader, messageFormat);
|
||||||
|
|
||||||
// REVIEW: Do we want to return a specific status code here if the connection has ended?
|
// REVIEW: Do we want to return a specific status code here if the connection has ended?
|
||||||
_logger.LogDebug("Received batch of {0} message(s) in '/send'", messages.Count);
|
_logger.LogDebug("Received batch of {0} message(s) in '/send'", messages.Count);
|
||||||
|
|
@ -449,7 +442,7 @@ namespace Microsoft.AspNetCore.Sockets
|
||||||
return connectionState;
|
return connectionState;
|
||||||
}
|
}
|
||||||
|
|
||||||
private IList<Message> ParseSendBatch(ref BytesReader payload, MessageFormat messageFormat)
|
private List<Message> ParseSendBatch(ref BytesReader payload, MessageFormat messageFormat)
|
||||||
{
|
{
|
||||||
var messages = new List<Message>();
|
var messages = new List<Message>();
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -109,6 +109,32 @@ namespace Microsoft.AspNetCore.Sockets.Tests
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task SendRequestsWithInvalidContentTypeAreRejected()
|
||||||
|
{
|
||||||
|
var manager = CreateConnectionManager();
|
||||||
|
var connectionState = manager.CreateConnection();
|
||||||
|
var dispatcher = new HttpConnectionDispatcher(manager, new LoggerFactory());
|
||||||
|
using (var strm = new MemoryStream())
|
||||||
|
{
|
||||||
|
var context = new DefaultHttpContext();
|
||||||
|
var services = new ServiceCollection();
|
||||||
|
services.AddOptions();
|
||||||
|
services.AddEndPoint<TestEndPoint>();
|
||||||
|
context.RequestServices = services.BuildServiceProvider();
|
||||||
|
context.Request.Path = "/send";
|
||||||
|
context.Request.QueryString = new QueryString($"?id={connectionState.Connection.ConnectionId}");
|
||||||
|
context.Request.ContentType = "text/plain";
|
||||||
|
context.Response.Body = strm;
|
||||||
|
|
||||||
|
await dispatcher.ExecuteAsync<TestEndPoint>("", context);
|
||||||
|
|
||||||
|
Assert.Equal(StatusCodes.Status400BadRequest, context.Response.StatusCode);
|
||||||
|
await strm.FlushAsync();
|
||||||
|
Assert.Equal("'text/plain' is not a valid Content-Type for send requests.", Encoding.UTF8.GetString(strm.ToArray()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
[Theory]
|
[Theory]
|
||||||
[InlineData(TransportType.LongPolling, 204)]
|
[InlineData(TransportType.LongPolling, 204)]
|
||||||
[InlineData(TransportType.WebSockets, 404)]
|
[InlineData(TransportType.WebSockets, 404)]
|
||||||
|
|
@ -417,8 +443,6 @@ namespace Microsoft.AspNetCore.Sockets.Tests
|
||||||
}
|
}
|
||||||
|
|
||||||
[Theory]
|
[Theory]
|
||||||
[InlineData("", "text", "Hello, World", "Hello, World", MessageType.Text)] // Legacy format
|
|
||||||
[InlineData("", "binary", "Hello, World", "Hello, World", MessageType.Binary)] // Legacy format
|
|
||||||
[InlineData(TextContentType, null, "T12:T:Hello, World;", "Hello, World", MessageType.Text)]
|
[InlineData(TextContentType, null, "T12:T:Hello, World;", "Hello, World", MessageType.Text)]
|
||||||
[InlineData(TextContentType, null, "T16:B:SGVsbG8sIFdvcmxk;", "Hello, World", MessageType.Binary)]
|
[InlineData(TextContentType, null, "T16:B:SGVsbG8sIFdvcmxk;", "Hello, World", MessageType.Binary)]
|
||||||
[InlineData(TextContentType, null, "T12:E:Hello, World;", "Hello, World", MessageType.Error)]
|
[InlineData(TextContentType, null, "T12:E:Hello, World;", "Hello, World", MessageType.Error)]
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue