Livt packages
Livt.Web
Version 1.0.0
Bounded HTTP routing, request parsing, response encoding, and Ethernet application composition for Livt.
Published files (63)
- HttpAllowedMethods.lvt
- HttpApplication.lvt
- HttpApplicationState.lvt
- HttpContentType.lvt
- HttpHeaderName.lvt
- HttpMatchResult.lvt
- HttpMethod.lvt
- HttpNetworkEndpoint.lvt
- HttpNetworkResponse.lvt
- HttpPath.lvt
- HttpPreparation.lvt
- HttpRequestCursor.lvt
- HttpRequestHeaders.lvt
- HttpRequestLine.lvt
- HttpRequestParser.lvt
- HttpRequestResult.lvt
- HttpRequestSyntax.lvt
- HttpResponse.lvt
- HttpResponseEncoder.lvt
- HttpResponseSyntax.lvt
- HttpRouteFallback.lvt
- HttpRouteMethods.lvt
- HttpRouter.lvt
- HttpServer.lvt
- HttpStatus.lvt
- HttpTcpFrame.lvt
- HttpTcpSequence.lvt
- HttpTcpState.lvt
- HttpTcpTransport.lvt
- HttpTransportPayload.lvt
- HttpTransportState.lvt
- HttpVersion.lvt
- IHttpApplication.lvt
- IHttpHandler.lvt
- IHttpRequest.lvt
- IHttpResponse.lvt
- IHttpRoute.lvt
- IHttpRouteMatcher.lvt
- Route.lvt
- RouteChain.lvt
- RouteDispatch.lvt
- RouteSelection.lvt
- StaticContent.lvt
src/http/Route.lvt
namespace Livt.Web.Http
using Livt.Net
/**
* Leaf binding one request/matcher and an exclusively owned handler lifecycle.
*/
component Route<R: IHttpRequest, M: IHttpRouteMatcher, H: IHttpHandler> : IHttpRoute
{
// Borrowed dependencies; matcher must use this same request.
request: R
matcher: M
handler: H
method: HttpMethod
// Frozen selection and whether handler cleanup is required.
dispatch: RouteDispatch
started: bool
preparation: HttpPreparation
/**
* Borrows one method/matcher/request binding and an exclusive handler lifecycle.
* The matcher must use this request; construction does not start the handler.
*/
new(method: HttpMethod, request: R, matcher: M, handler: H)
{
this.method = method
this.request = request
this.matcher = matcher
this.handler = handler
}
/**
* Selects over the shared published request without beginning a handler.
* NotReady may retry; other outcomes remain frozen until End.
*/
override fn Select() RouteDispatch
{
if (dispatch != RouteDispatch.Idle && dispatch != RouteDispatch.NotReady) {
return dispatch
}
if (HttpRouteMethods.FromMethod(method) == HttpAllowedMethods.None) {
dispatch = RouteDispatch.Failed
return dispatch
}
if (!request.IsReady()) {
dispatch = RouteDispatch.NotReady
return dispatch
}
var result = matcher.TryMatch()
dispatch = RouteDispatch.Failed
if (result == HttpMatchResult.NotReady) {
dispatch = RouteDispatch.NotReady
}
elif (result == HttpMatchResult.NoMatch) {
dispatch = RouteDispatch.NotFound
}
elif (result == HttpMatchResult.Match) {
dispatch = RouteDispatch.MethodNotAllowed
if (request.GetMethod() == method) {
dispatch = RouteDispatch.Selected
}
}
return dispatch
}
/**
* Returns the supported-method union for matching paths.
* This describes route selection, not a prepared response or a wildcard method.
*/
override fn GetMatchedMethods() HttpAllowedMethods
{
if (dispatch == RouteDispatch.Selected || dispatch == RouteDispatch.MethodNotAllowed) {
return HttpRouteMethods.FromMethod(method)
}
return HttpAllowedMethods.None
}
/**
* Starts preparation once for the accepted selection; repeated calls must not
* repeat accepted application actions. Pending work resumes through Poll.
*/
override fn Begin() HttpPreparation
{
if (dispatch != RouteDispatch.Selected) {
return HttpPreparation.Idle
}
if (started) {
return preparation
}
started = true
var result = handler.Begin()
preparation = result
return result
}
/**
* Resumes pending preparation without restarting accepted actions.
* Prepared or Failed remains terminal until End.
*/
override fn Poll() HttpPreparation
{
if (!started) {
return HttpPreparation.Idle
}
if (preparation == HttpPreparation.Pending) {
var result = handler.Poll()
preparation = result
}
if (preparation == HttpPreparation.Prepared && !handler.IsReady()) {
preparation = HttpPreparation.Failed
}
return preparation
}
/**
* Ends only a started handler, then resets selection and preparation.
* Requires stopped response consumers; the request owner retains its storage.
*/
override fn End()
{
if (started) {
handler.End()
}
started = false
preparation = HttpPreparation.Idle
dispatch = RouteDispatch.Idle
}
/**
* Reports current publication availability, not a reservation.
* Keep the borrowed providers stable until all consumers finish.
*/
override fn IsReady() bool
{
if (!started) {
return false
}
return handler.IsReady()
}
/**
* Returns the selected response status; use only while IsReady is true.
*/
override fn GetStatus() HttpStatus
{
if (!started) {
return HttpStatus.Unknown
}
return handler.GetStatus()
}
/**
* Returns the selected body media type; use only while IsReady is true.
*/
override fn GetContentType() HttpContentType
{
if (!started) {
return HttpContentType.Unknown
}
return handler.GetContentType()
}
/**
* Returns the selected response Allow set, not the routing tree's match set.
* Use only while IsReady is true; None omits the Allow header.
*/
override fn GetAllowedMethods() HttpAllowedMethods
{
if (!started) {
return HttpAllowedMethods.None
}
return handler.GetAllowedMethods()
}
/**
* Returns the currently advertised byte extent, or zero without publication.
* The extent is a snapshot; it does not reserve the backing storage.
*/
override fn GetAvailableLength() int
{
if (!started) {
return 0
}
return handler.GetAvailableLength()
}
/**
* Reads a zero-based byte within the published extent. Check PacketDataResult
* before using value; keep all borrowed providers stable throughout the read.
*/
override fn TryRead(index: int, value: out byte) PacketDataResult
{
value = 0x00
if (!started) {
return PacketDataResult.NotReady
}
return handler.TryRead(index, value)
}
}