nim-presto/presto/secureserver.nim

109 lines
3.8 KiB
Nim

#
# REST API framework implementation
# (c) Copyright 2021-Present
# Status Research & Development GmbH
#
# Licensed under either of
# Apache License, version 2.0, (LICENSE-APACHEv2)
# MIT license (LICENSE-MIT)
import std/options
import chronos, chronos/apps/http/shttpserver
import chronicles
import stew/results
import route, common, segpath, servercommon, serverprivate, agent
export options, chronos, shttpserver, servercommon, chronicles, agent
{.push raises: [].}
type
SecureRestServer* = object of RootObj
server*: SecureHttpServerRef
router*: RestRouter
errorHandler*: RestRequestErrorHandler
SecureRestServerRef* = ref SecureRestServer
proc new*(t: typedesc[SecureRestServerRef],
router: RestRouter,
address: TransportAddress,
tlsPrivateKey: TLSPrivateKey,
tlsCertificate: TLSCertificate,
serverIdent: string = PrestoIdent,
secureFlags: set[TLSFlags] = {},
serverFlags = {HttpServerFlags.NotifyDisconnect},
socketFlags: set[ServerFlags] = {ReuseAddr},
serverUri = Uri(),
maxConnections: int = -1,
backlogSize: int = DefaultBacklogSize,
bufferSize: int = 4096,
httpHeadersTimeout = 10.seconds,
maxHeadersSize: int = 8192,
maxRequestBodySize: int = 1_048_576,
requestErrorHandler: RestRequestErrorHandler = nil,
dualstack = DualStackType.Auto,
errorType: type = cstring
): Result[SecureRestServerRef, errorType] =
var server = SecureRestServerRef(
router: router,
errorHandler: requestErrorHandler
)
proc processCallback(rf: RequestFence): Future[HttpResponseRef] =
processRestRequest(server, rf)
let sres = SecureHttpServerRef.new(address, processCallback, tlsPrivateKey,
tlsCertificate, serverFlags, socketFlags,
serverUri, serverIdent, secureFlags,
maxConnections, bufferSize, backlogSize,
httpHeadersTimeout, maxHeadersSize,
maxRequestBodySize, dualstack = dualstack)
if sres.isOk():
server.server = sres.get()
ok(server)
else:
when errorType is cstring:
error "REST service could not be started", address = address,
reason = sres.error
err("Could not create HTTP server instance")
elif errorType is string:
err(sres.error)
else:
{.fatal: "Error type is not supported".}
proc localAddress*(rs: SecureRestServerRef): TransportAddress =
## Returns `rs` bound local socket address.
rs.server.instance.localAddress()
proc state*(rs: SecureRestServerRef): RestServerState =
## Returns current REST server's state.
case rs.server.state
of HttpServerState.ServerClosed:
RestServerState.Closed
of HttpServerState.ServerStopped:
RestServerState.Stopped
of HttpServerState.ServerRunning:
RestServerState.Running
proc start*(rs: SecureRestServerRef) =
## Starts REST server.
rs.server.start()
notice "Secure REST service started", address = $rs.localAddress()
proc stop*(rs: SecureRestServerRef) {.async.} =
## Stop REST server from accepting new connections.
await rs.server.stop()
notice "Secure REST service stopped", address = $rs.localAddress()
proc drop*(rs: SecureRestServerRef): Future[void] =
## Drop all pending connections.
rs.server.drop()
proc closeWait*(rs: SecureRestServerRef) {.async.} =
## Stop REST server and drop all the pending connections.
await rs.server.closeWait()
notice "Secure REST service closed", address = $rs.localAddress()
proc join*(rs: SecureRestServerRef): Future[void] =
## Wait until REST server will not be closed.
rs.server.join()