using System.Net; namespace SimpleHttpServer; public class RequestContext : IDisposable { public HttpListenerContext ListenerContext { get; } private StreamReader? reqReader; public StreamReader ReqReader => reqReader ??= new(ListenerContext.Request.InputStream); private StreamWriter? respWriter; public StreamWriter RespWriter => respWriter ??= new(ListenerContext.Response.OutputStream) { NewLine = "\n" }; public RequestContext(HttpListenerContext listenerContext) { ListenerContext = listenerContext; } public async Task WriteLineToRespAsync(string resp) => await RespWriter.WriteLineAsync(resp); public async Task WriteToRespAsync(string resp) => await RespWriter.WriteAsync(resp); public void SetStatusCode(int status) { ListenerContext.Response.StatusCode = status; ListenerContext.Response.StatusDescription = GetDescriptionFromStatusCode(status); } public void SetStatusCode(HttpStatusCode status) => SetStatusCode((int) status); public async Task SetStatusCodeAndDisposeAsync(int status) { using (this) { SetStatusCode(status); await WriteToRespAsync("\n\n"); } } public async Task SetStatusCodeAndDisposeAsync(HttpStatusCode status) { using (this) { SetStatusCode((int) status); await WriteToRespAsync("\n\n"); } } public async Task SetStatusCodeAndDisposeAsync(int status, string description) { using (this) { ListenerContext.Response.StatusCode = status; ListenerContext.Response.StatusDescription = description; await WriteToRespAsync("\n\n"); } } public async Task SetStatusCodeAndDisposeAsync(HttpStatusCode status, string description) => await SetStatusCodeAndDisposeAsync((int) status, description); void IDisposable.Dispose() { reqReader?.Dispose(); respWriter?.Dispose(); GC.SuppressFinalize(this); } // src: https://en.wikipedia.org/wiki/List_of_HTTP_status_codes private static string GetDescriptionFromStatusCode(int status) => status switch { 100 => "Continue", 101 => "Switching Protocols", 102 => "Processing", 103 => "Early Hints", 200 => "OK", 201 => "Created", 202 => "Accepted", 203 => "Non-Authoritative Information", 204 => "No Content", 205 => "Reset Content", 206 => "Partial Content", 207 => "Multi-Status", 208 => "Already Reported", 226 => "IM Used", 300 => "Multiple Choices", 301 => "Moved Permanently", 302 => "Found", 303 => "See Other", 304 => "Not Modified", 305 => "Use Proxy", 306 => "Switch Proxy", 307 => "Temporary Redirect", 308 => "Permanent Redirect", 400 => "Bad Request", 401 => "Unauthorized", 402 => "Payment Required", 403 => "Forbidden", 404 => "Not Found", 405 => "Method Not Allowed", 406 => "Not Acceptable", 407 => "Proxy Authentication Required", 408 => "Request Timeout", 409 => "Conflict", 410 => "Gone", 411 => "Length Required", 412 => "Precondition Failed", 413 => "Payload Too Large", 414 => "URI Too Long", 415 => "Unsupported Media Type", 416 => "Range Not Satisfiable", 417 => "Expectation Failed", 421 => "Misdirected Request", 422 => "Unprocessable Content", 423 => "Locked", 424 => "Failed Dependency", 425 => "Too Early", 426 => "Upgrade Required", 428 => "Precondition Required", 429 => "Too Many Requests", 431 => "Request Header Fields Too Large", 451 => "Unavailable For Legal Reasons", 500 => "Internal Server Error", 501 => "Not Implemented", 502 => "Bad Gateway", 503 => "Service Unavailable", 504 => "Gateway Timeout", 505 => "HTTP Version Not Supported", 506 => "Variant Also Negotiates", 507 => "Insufficient Storage", 508 => "Loop Detected", 510 => "Not Extended", 511 => "Network Authentication Required", _ => "Unknown", }; }