Releases: sisk-http/core
v1.6.0
This update brings significant improvements to HTTP engine architecture, a new file server system, and framework enhancements.
HTTP File Server
Introduced the new HttpFileServer system for serving static files efficiently and flexibly:
- Optimized streaming with
Rangeheader support for audio and video - Customizable converters through
HttpFileServerFileConverter - Configurable directory listing
- Automatic content negotiation based on MIME types
var route = HttpFileServer.CreateServingRoute("/static", "./public");
router += route;
// Or with custom configuration
var handler = new HttpFileServerHandler("./public") {
AllowDirectoryListing = true,
// Add custom converters
};
var route = HttpFileServer.CreateServingRoute("/files", handler);The new FileContent class allows returning files with automatic streaming and range request support:
router.SetRoute(RouteMethod.Get, "/download", request => {
return new FileContent("./video.mp4");
});The HttpFileAudioConverter and HttpFileVideoConverter converters provide automatic support for range requests in media files, enabling seeking in audio/video players.
HTTP Engine Improvements
Significant improvements to HTTP engine abstraction:
- Nova interface
HttpServerEngineContext: Abstração completa do ciclo de vida de requisições HTTP HttpServerEngineWebSocket: Interface abstrata para WebSocket em diferentes engines- Mecanismos de event loop: Suporte através de
HttpServerEngineContextEventLoopMecanism - Melhor integração SSL: Classe
ListeningHostSslOptionspara configuração SSL por listening host
var host = new ListeningHost("https://localhost:5000") {
SslOptions = new ListeningHostSslOptions {
Certificate = myCertificate
}
};Logging Improvements
RotatingLogPolicyCompressor: Interface for automatic compression of rotated logsGZipRotatingLogPolicyCompressor: Built-in implementation with GZip compressionPrefixedLogStream: Improvements to prefixed log stream
var rotatingPolicy = new RotatingLogPolicy {
Compressor = new GZipRotatingLogPolicyCompressor()
};HTTP Server Handler Improvements
- Handler execution ordering: Added
Priorityproperty toHttpServerHandlerto control execution order HttpServerHandlerSortingComparer: New comparer for sorting handlers by priority (lower values execute first)HttpServerHandlerRepository: Changed internal storage fromList<T>toSortedSet<T>for automatic priority-based ordering
WebSocket Improvements
- Fix: Corrections to WebSocket connection management
- Improvements to
HttpWebSocketConnectionCollection - Better handling of closed connections
Other Changes
HttpRequestEventSource: Improvements to Server-Sent Events systemCertificateHelper: New helper class for SSL certificate managementHttpRequest.DisconnectToken: Improvements to disconnection detectionHttpServerExecutionResult: New fields for better execution tracking
Breaking Changes
ListeningHost: SSL properties moved toListeningHostSslOptionsHttpServerEngine: New interface with additional abstract methods- Some method signatures in engines have been changed to support the new contexts
Bug Fixes
- Fixed: Simplified connection closed check in HTTP request parsing
- Fixed: HTTP body drainage corrected
- Fixed: Issues with chunked encoding in requests
- Fixed: Better abort handling in HTTP components
- Fixed: Optimized HTTP header parsing and handling
v1.5.2
v1.5
Contributions
- ResolveEndpoint optimized so that if an IP address is explicitly specified, that IP address is used by @Sascha-L in #23
HTTP engine abstraction
The Sisk Framework is now independent of HttpListener.
In this update, all HttpListener-dependent mechanisms have been abstracted into what are called HTTP Engines, which control the abstraction level between the framework and the incoming HTTP components.
With this change, Sisk will be able to use other HTTP processors, such as Cadente Project, Kestrel, or other servers.
Each server can bring features not previously supported natively in Sisk, such as SSL, Quic, pipelining, etc.
Currently, Sisk continues to use .NET's HttpListener as it remains the most stable. Follow and contribute to the development of the Cadente engine for Sisk here.
CORS Improvements
In this update, two global constants have been introduced:
CrossOriginResourceSharingHeaders.AutoFromRequestMethodCrossOriginResourceSharingHeaders.AutoFromRequestHeaders
The behavior is similar to CrossOriginResourceSharingHeaders.AutoAllowOrigin: the server responds with CORS headers according to the request:
using var host = HttpServer.CreateBuilder()
.UseCors(new CrossOriginResourceSharingHeaders(
allowOrigin: CrossOriginResourceSharingHeaders.AutoAllowOrigin,
allowMethods: [CrossOriginResourceSharingHeaders.AutoFromRequestMethod],
allowHeaders: [CrossOriginResourceSharingHeaders.AutoFromRequestHeaders],
exposeHeaders: [HttpKnownHeaderNames.ContentType, "X-Authenticated-Account-Id"],
allowCredentials: true))
...Web socket API breaking changes
The entire API for the HttpWebSocket class was changed. The motivation for this change was to reduce async/await errors, since the internal WebSocket object doesn't provide a synchronous API. This API rewrite fixes memory leak issues, error handling in asynchronous events, and message pooling.
- No more synchronous methods or events.
- All
Send()methods were removed. UseSendAsync()overloads instead. - No more
WaitForExit()methods. UseReceiveMessageAsync()with a cancellation token or timeout instead. - No more
Close(). UseCloseAsync()instead.
Read the updated docs for more info.
Bug fixes and other changes
- Entirely refactored the
LogStreamcode:- General improvements and fixes in concurrent writing.
- Improvements in asynchronous and synchronous processing.
- Improvements in the shared
LogStreamsingleton. - Fixes for
FlushandFlushAsyncdischarge. - Fixed a bug that caused the circular buffer to come in reverse.
- Implemented
IAsyncDisposable.
- General fixes and improvements in
CircularBuffer<T>. - Added
HttpRequest.DisconnectToken. Note: this feature may not be compatible with all HTTP engines. - Added the
LogModeproperty for theHttpContextclass. With this property, you can decide which log modes are enabled for the current context, which will override the current route log mode. - Added the
HttpContext.GetCurrentContext()method, which returns the currentHttpContextif the current thread is running on a HTTP request context. - Added the
HttpResponse.GetHeaderValue()helper method, which attempts to get an header value from both definedHttpResponse.Content.Headersproperty orHttpResponse.Headers. - Added the
HttpServerConfiguration.DefaultAccessLogFormatconstant. - Added the
TypedValueDictionary.GetValueandTypedValueDictionary.SetValuehelper methods. - Added the
MimeHelper.IsPlainTextMimeTypehelper method. - Added the
{:header}constant literal for the log-formatting options. - Improved exception-handling for forwarding resolvers.
- Fixed an issue where the
ForwardingResolvermethods could throw an exception before the initialization of theHttpRequestobject, which caused theHttpServerExecutionResult.HttpRequestto have an nullHttpRequestobject. - Fixed an possible stack overflow issue when using
InitializationParameterCollection.ContainsKey. - Fixed an issue where the HTTP server were compressing already compressed contents through the
EnableAutomaticResponseCompressionoption. - Fixed an issue where the HTTP server were trying to send responses generated by the
Router.CallbackErrorHandler,Router.NotFoundErrorHandler,Router.MethodNotAllowedErrorHandlerto contexts where was streaming content. - Fixed issues where some HTTP headers could be set after sending content on the
HttpResponseStreamManagerclass. - Fixed issues in the access log formatter.
- Fixed an issue where the HTTP server was not enabling error-logging for user-handled errors.
Full Changelog: 1.4.3...1.5.0
v1.4.3
Full Changelog: 1.4.2...1.4.3
Content compression:
- Added the
HttpServerConfiguration.EnableAutomaticResponseCompressionproperty.
Streaming:
- Removed the
GetLinkedCancellationSourcemethod for bothHttpRequestEventSourceandHttpWebSocketclasses which was added in v1.4.2. Sorry for that!
Bug fixes:
- Fixed an issue where closing web-socket
WaitNextmethods were not returning after the WS connection being closed. - Fixed an issue where multiple WS messages were being discarded when using
WaitNext, because they were not enqueued. Now it is enqueued. - Fixed an issue where empty WS messages were closing the connection by the server side.
- Fixed an issue where the HTTP server weren't treating HEAD requests as GET requests to GET routes.
- Fixed an issue where the HTTP server was allowing sending content in prohibited methods (HEAD and CONNECT).
- Fixed an issue where the
HttpServerExecutionResult.Responsewere always null. - Fixed an issue where the access log were not correctly logging HTTP response status codes.
- Removed the obsolete
HttpServerConfiguration.DefaultCultureInfoproperty.
v1.4.2
Full Changelog: 1.4.1...1.4.2
Multipart objects:
- Added the
MultipartFormCollection.GetFile(string)method. - Added the
MultipartFormCollection.Filesproperty. - Added the
MultipartObject.IsFileproperty.
HTTP Requests:
- Added the
HttpRequest.DefaultJsonSerializerOptionsstatic property. - Added the
HttpRequest.GetBodyContentsmethod. - Added the
HttpRequest.GetBodyContentsAsyncmethod. - Several improvements to the
HttpRequest.GetJsonContentoverloads. - Several improvements to the
HttpRequest.GetFormContentAsyncmethod.
Hosting:
- Added the
InitializationParameterCollection.GetStringValue(string)method.
HTML content:
- Added the
HtmlContent(ReadOnlySpan<byte> contents, Encoding encoding)constructor. - Added the
HtmlContent(ReadOnlySpan<byte> contents)constructor.
Logging:
- Added a bunch of async methods, such as
WriteLineAsynctoLogStream. - Added the
PrefixedLogStreamclass. - Breaking: the
LogStream.WriteExceptionis not virtual anymore.
Streaming:
- Added the
GetLinkedCancellationSourcemethod for bothHttpRequestEventSourceandHttpWebSocketclasses.
Bug fixes:
- Fixed an issue where
IAsyncEnumerable<>andIEnumerable<>results were streaming the results outside the router context, which allowed exceptions to not be handled correctly. - Fixed an typo error in the
MultipartObject.HasContentsproperty documentation. - Fixed an issue where the HTTP server was returning an
400 OKand500 Okerrors for unhandled exceptions instead the right description codes.
v1.4.1
Full Changelog: 1.4.0.1...1.4.1
- Added the
Router.MatchRouteExpressionmethod. - Added the
Router.IsRouteExpressionsOverlapmethod. - Added the
CrossOriginResourceSharingHeaders.AutoAllowOriginconstant. - Added the
CrossOriginResourceSharingHeaders(string?, string[]?, string[]?, string[]?, string[]?, TimeSpan?)constructor. - Added the
TypedValueDictionary.GetOrAdd<T>method. - Added more mime types to the inline mime type list.
- Added the
[FlagsAttribute]to theRequestHandlerExecutionModeenum. - Added the
HttpRequest.GetMultipartFormContentAsyncmethod. - Added the
HttpRequest.GetFormContentAsyncmethod. - Added the
HttpRequest.GetEventSourceAsyncmethod. - Added the
HttpRequest.GetWebSocketAsyncmethod. - Added the
HttpWebSocket.SendAsyncmethod. - Added the
HttpRequestEventSource.SendAsyncmethod. - Added the
HttpRequest.GetJsonContentandHttpRequest.GetJsonContentAsyncmethods. - Made the
HttpWebSocketandHttpRequestEventSourceIDisposable. - Fixed the wrong return type for the
StringValue.GetSingle()method. - Fixed an issue where the log formatter was formatting the
%ticonstant with the month number instead the date and time minute. - Deprecated the
HttpServerConfiguration.DefaultCultureInfoproperty. UseCultureInfo.DefaultThreadCurrentCultureinstead.
v1.4
Full Changelog: 1.3.2.0...1.4.0.1
v1.4
Goodbye, HttpServerFlags!
Some "advanced" properties of the server, present in the old HttpServerFlags, have been migrated to the HttpServerConfiguration object. This means that the HttpServerFlags class has also been removed, along with all references to it.
See below for the migrated and removed properties:
| Property name | State | Observations |
|---|---|---|
| ThrowContentOnNonSemanticMethods | ❌ Removed | See note 1. |
| PreventResponseContentsInProhibitedMethods | ❌ Removed | See note 1. |
| AsyncRequestProcessing | ➡ Migrated | |
| HeaderNameRequestId | ❌ Removed | |
| SendCorsHeaders | ❌ Removed | See note 2. |
| TreatHeadAsGetMethod | ❌ Removed | See note 3. |
| OptionsLogMode | ➡ Migrated | |
| SendSiskHeader | ➡ Migrated | |
| WebSocketBufferSize | ❌ Removed | |
| RequestStreamCopyBufferSize | ❌ Removed | |
| NormalizeHeadersEncodings | ➡ Migrated | |
| ForceTrailingSlash | ➡ Migrated | |
| IdleConnectionTimeout | ➡ Migrated | |
| EnableNewMultipartFormReader | ❌ Removed | See other changes. |
| ConvertIAsyncEnumerableIntoEnumerable | ➡ Migrated |
Note 1: This is a overreal design change in Sisk. In summary, the framework will no longer treat the developer like a baby and prevent them from performing illegal operations according to the HTTP RFC. Instead, Sisk will allow it, but the responsibility of following the HTTP fundamentals now lies with the user, not the framework.
Note 2: The server will no longer listen to the
SendCorsHeadersproperty. To not send CORS headers, you can use an empty or null instance of CrossOriginResourceSharingHeaders.Empty in your ListeningHost. Another option is to disable the use of CORS for that route with the Route.UseCors property. Additionally, you can define routes of type RouteMethod.Options to manually handle OPTIONS requests.
Note 3: The HTTP server will no longer treat HEAD requests as GET. You can still define routes with RouteMethod.Head and handle them directly, or use RouteMethod.Get | RouteMethod.Head to handle a route for two different methods, and get the request method with HttpRequest.Method.
Easy compressed contents
Added 3 new HTTP contents:
These contents provides a easy way to compress HTTP contents of a response on-the-fly, like:
router.MapGet("/hello.html", request => {
string myHtml = "...";
return new HttpResponse () {
Content = new GZipContent(new HtmlContent(myHtml))
};
});You can also extend your own compressing content from the CompressedContent class.
Auto-dispose IDisposable context values
The new DisposeDisposableContextValues property allows values that are IDisposable to be automatically disposed of at the end of an HTTP context, removing the need to create a RequestHandler for this task.
Other changes
- Added the
Router.CheckForRouteCollisionsproperty. - Added the
StringKeyStore.AsStringValueCollectionmethod. - Removed the experimental warning from the
HttpContext.Currentproperty. - Removed the old Multipart Form parser.
- Fixed an issue where the served
HttpContentwasn't being correctly disposed in certain situations. - Deprecated the
HttpServerExecutionResult.DnsFailedfield. - Breaking: removed the
HttpServerHostContextBuilder.UseFlagsmethod. - Breaking: removed the
StringValue.GetParsable<T>method. You should use theStringValue.Get<T>method instead.
v1.3.2
- Fixed a bug where the HTTP server was not binding correctly to prefixes that contained paths on hosts that are not "localhost". - #17
- Fixed a bug where the router's collision detector was not working correctly when routes had exactly the same definitions.
- Fixed a bug where
[RouteAttribute]attributes adjacent to other attributes were not being correctly assigned to routes
v1.3.1
v.1.3.1
- Breaking: removed the
HttpServerConfiguration.DefaultEncodingproperty. #0c7e36~0f4, at 68 - Added experimental support for
IAsyncEnumerable<T>responses. Can be disabled by disabling the newHttpServerFlags.ConvertIAsyncEnumerableIntoEnumerableflag. - Added more constructors for
HttpHeaderCollectionclass. #93f8ad~294, from 30 to 59 - Added more constructors for
StringKeyStoreclass. #93f8ad~efb, at 51 - Added more constructors for
Routerclass. #0c7e36~42b, at 93 - Added the
StringKeyStore.AddRangemethod. #93f8ad~efb, at 292 - The Multipart object reader now decodes the request payload using the request encoding instead UTF-8. [#93f8ad~294](#93f8ad~294, from 30 to 59)
- Added the
HttpContext.IsRequestContextproperty. #710492~3a5, at 36 - Added the
HttpRequest.Abortmethod (again). #710492~89d, at 516 - Sisk now uses
StringComparer.Ordinalin most places which doens't requires invariant comparisons. - Other minor changes and improvements.
Sisk.SslProxy
- Newly trusted certificates are now inserted in the user key store, not the machine key store. #bd9de4~391, from 106 to 107
- Fixed an issue where the DNS resolver could resolve to an IPv6 address in an deactivated network system. #2e29d1
v1.3
v.1.3
Sisk 1.3 is being released today! This update brings performance improvements, another way to write your favorite APIs, and something similar to dependency injection.
Sisk's commitment remains the same: to be simple to develop a quality HTTP application. Sisk has no dependencies other than the .NET ecosystem itself, and all its code is still less than 1KB in total. Sisk has a minimal footprint, focusing performance on your application's layer, not the server.
We would also like to showcase the new logo of the project. It is more modern while still referencing what the project used to be.
Performance improvements
Sisk has a limitation: it depends on the current implementation of HttpListener to work. This implementation is great on Windows and has performance comparable to ASP.NET, but in recent tests, we found that the managed implementation of HttpListener lags significantly behind ASP.NET's Kestrel, which happens outside Windows environments. Even so, Sisk still manages to be much more performant and efficient than many other development frameworks in other languages. Our goal is not to be better than ASP.NET, but the closer we get to its performance, the more viable the choice of Sisk becomes for more projects.
In version 1.3, we achieved an average performance increase of 15% overall for request processing. This is because we improved the way the server sends the content of a response to the client. The HttpResponse object depends on HttpContent to define content to send to the client, and previously, this object had to be serialized through HttpContent.ReadAsByteArrayAsync. The problem is that many contents are based on ByteArrayContent, and when calling this method on this type of content, a memory buffer was created, and the response bytes were copied to this buffer. Then, this buffer was copied to the response's output stream.
Thanks to UnsafeAccessor in .NET 8, we can access the response bytes directly, without the need to create this secondary buffer. This greatly improved overall performance.
In addition, there were performance improvements outside of the request processor as well. Improvements were made in the way the server writes messages to the access log and deserializes multipart content.
Static HttpContexts
An experimental feature is to expose the current HttpContext of a request in a local context of the execution thread. This allows you to expose members of a request outside the request method, greatly improving the readability of your code. The code snippet below shows an abstract class that functions as an API controller with an embedded database.
public abstract class Controller : RouterModule
{
public DbContext Database
{
// Create or get an new DbContext instance
get => HttpContext.Current.RequestBag.GetOrAdd(() => new DbContext());
}
// Exposing the HttpRequest instance is supported too
public HttpRequest Request { get => HttpContext.Current.Request; }
protected override void OnSetup(Router parentRouter)
{
base.OnSetup(parentRouter);
HasRequestHandler(RequestHandler.Create(
execute: (req, ctx) =>
{
// disposes the current DbContext if used
ctx.RequestBag.GetOrDefault<DbContext>()?.Dispose();
return null;
},
executionMode: RequestHandlerExecutionMode.AfterResponse));
}
}And use this implementation with methods that do not have an HttpRequest parameter, as you already have a Request in your controller instance.
[RoutePrefix("/api/posts")]
public class PostsController : Controller
{
[RouteGet]
public IEnumerable<Blog> ListPosts()
{
return Database.Posts
.Where(post => post.AuthorId == AuthenticatedUser.Id)
.ToList();
}
[RouteGet("<id>")]
public Post GetPost()
{
int blogId = Request.RouteParameters["id"].GetInteger();
Post? post = Database.Posts
.FirstOrDefault(post => post.Id == blogId && post.AuthorId == AuthenticatedUser.Id);
return post ?? new HttpResponse(404);
}
}You can read more about this feature in the documentation.
Full changelog
New features:
- New logo.
- Added support for .NET 9.
- Added the
StringKeyStore.SetRangemethod. - Added the
TypedValueDictionary.GetOrDefault<T>method. - Added the
TypedValueDictionary.GetOrAdd<T>method. - Added the
TypedValueDictionary.GetOrAddAsync<T>method. - Added the
HttpRequest.Uriproperty. - Added the
HttpServerExecutionResult.Elapsedproperty. - Added the
HttpContext.Currentstatic property. - Added the
HttpResponseExtensions.WithHeader(StringKeyStore)method. - Added the
MimeHelper.DefaultMimeTypestatic property. - Added the
MimeHelper.IsBrowserKnownInlineMimeType(string)method. - Added the
HttpServerFlags.PreventResponseContentsInProhibitedMethodsflag. - Added the
Route.Get,Route.Post,Route.Put,Route.Delete,Route.Head,Route.Options,Route.AnyandRoute.Patchstatic methods. - Added the
RouterModule.OnSetupvirtual method. - Added the
CookieHelperstatic class.
Changes:
- Improved the path matching algorithm.
- Improved the log writer algorithm.
- The HTTP server will now show an warning when it's starting without any route defined.
- Changed type from
Router.ActionfromRouteActiontoDelegate. - Changed return type from
TypedValueDictionary.Unsetfromvoidtobool. - Fixed when the HTTP server was starting with one random port and defined ports when using portable configurations.
Fixes:
- Fixed the
TypedValueDictionary.IsSet<T>attribute usage. - Fixed an issue where byte counts were being calculated with decimals in
SizeHelper.HumanReadableSize.
Breaking changes:
- Removed the
HttpKnownHeaderNames.Frommember. - Removed the
HttpRequest.GetQueryValuemethods. - Removed the
HttpServer.GetVersion()method. You can still use theHttpServer.PoweredByproperty instead. - Route/paths parameters will not be added into
HttpRequest.Queryanymore. You should use theHttpRequest.RouteParametersproperty instead. - Made
CookieHelperand static class and removed it from all classes who used it. You still can use theSetCookiemethods from where it was defined. - Deprecated the
HttpServerConfiguration.DefaultEncodingproperty.
Thank you for using Sisk!

