118 lines
No EOL
3.7 KiB
C#
118 lines
No EOL
3.7 KiB
C#
using System.Text;
|
|
using Uwaa.HTTP.Websockets;
|
|
|
|
namespace Uwaa.HTTP;
|
|
|
|
public class SwitchingProtocols : HttpResponse
|
|
{
|
|
/// <summary>
|
|
/// Called once a HTTP request is upgrade to a websocket.
|
|
/// </summary>
|
|
public readonly WebsocketHandler Callback;
|
|
|
|
internal SwitchingProtocols(string acceptKey, string? chosenProtocol, WebsocketHandler callback) : base(101, "Switching Protocols", new HttpFields())
|
|
{
|
|
Fields.WebSocketAccept = acceptKey;
|
|
Fields.WebSocketProtocol = chosenProtocol;
|
|
Fields.Upgrade = "websocket";
|
|
Fields.Connection = ConnectionType.Upgrade;
|
|
Callback = callback;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Contains the status code, status message, fields, and content of a HTTP response.
|
|
/// </summary>
|
|
public class HttpResponse
|
|
{
|
|
public static HttpResponse OK(HttpContent? content = null) => new HttpResponse(200, "OK", content);
|
|
|
|
public static HttpResponse Redirect(string location) => new HttpResponse(301, "Redirect", new HttpFields() { Location = location });
|
|
|
|
public static HttpResponse BadRequest(HttpContent? content = null) => new HttpResponse(400, "Bad request", content);
|
|
|
|
public static HttpResponse Forbidden(HttpContent? content = null) => new HttpResponse(403, "Forbidden", content);
|
|
|
|
public static HttpResponse NotFound(HttpContent? content = null) => new HttpResponse(404, "Not found", content);
|
|
|
|
public static HttpResponse MethodNotAllowed(HttpContent? content = null) => new HttpResponse(405, "Method not allowed", content);
|
|
|
|
public static HttpResponse NotAcceptable(HttpContent? content = null) => new HttpResponse(406, "Not acceptable", content);
|
|
|
|
public static HttpResponse InternalServerError(HttpContent? content = null) => new HttpResponse(500, "Internal server error", content);
|
|
|
|
public static implicit operator HttpResponse(HttpContent value) => OK(value);
|
|
|
|
public static implicit operator HttpResponse(HttpContent? value) => value == null ? NotFound(value) : OK(value);
|
|
|
|
|
|
|
|
public readonly int StatusCode;
|
|
|
|
public readonly string StatusMessage;
|
|
|
|
/// <summary>
|
|
/// HTTP header fields included in the response.
|
|
/// </summary>
|
|
public readonly HttpFields Fields;
|
|
|
|
/// <summary>
|
|
/// The body of the HTTP body, if any.
|
|
/// </summary>
|
|
public readonly HttpContent? Content;
|
|
|
|
public HttpResponse(int statusCode, string statusMessage, HttpContent? body = null) : this(statusCode, statusMessage, new HttpFields(), body)
|
|
{
|
|
}
|
|
|
|
public HttpResponse(int statusCode, string statusMessage, HttpFields fields, HttpContent? body = null)
|
|
{
|
|
StatusCode = statusCode;
|
|
StatusMessage = statusMessage;
|
|
Fields = fields;
|
|
Content = body;
|
|
}
|
|
|
|
internal async Task WriteTo(HttpStream stream)
|
|
{
|
|
if (StatusCode == 0)
|
|
return;
|
|
|
|
StringBuilder sb = new StringBuilder();
|
|
|
|
void writeField(string name, string value)
|
|
{
|
|
sb.Append(name);
|
|
sb.Append(": ");
|
|
sb.Append(value);
|
|
sb.Append("\r\n");
|
|
}
|
|
|
|
sb.Append("HTTP/1.1 ");
|
|
sb.Append(StatusCode);
|
|
sb.Append(' ');
|
|
sb.Append(StatusMessage);
|
|
sb.Append("\r\n");
|
|
|
|
if (Content.HasValue)
|
|
{
|
|
Fields.ContentLength = Content.Value.Content.Length;
|
|
Fields.ContentType = Content.Value.Type.ToString();
|
|
}
|
|
else
|
|
{
|
|
Fields.ContentLength = 0;
|
|
Fields.ContentType = null;
|
|
}
|
|
|
|
Fields.EmitAll(writeField);
|
|
sb.Append("\r\n");
|
|
|
|
await stream.Write(Encoding.ASCII.GetBytes(sb.ToString()));
|
|
|
|
if (Content.HasValue)
|
|
await stream.Write(Content.Value.Content);
|
|
|
|
await stream.Flush();
|
|
}
|
|
} |