From 6487ef65d0f98a9c8c9a163cd3bc02540ebb3367 Mon Sep 17 00:00:00 2001 From: Emery Hemingway Date: Mon, 8 Apr 2024 20:38:49 +0100 Subject: [PATCH] http_driver: add 504 binding timeouts --- src/syndicate/drivers/http_driver.nim | 24 +++++++++++++++++++----- 1 file changed, 19 insertions(+), 5 deletions(-) diff --git a/src/syndicate/drivers/http_driver.nim b/src/syndicate/drivers/http_driver.nim index ab754e3..04ea1a6 100644 --- a/src/syndicate/drivers/http_driver.nim +++ b/src/syndicate/drivers/http_driver.nim @@ -2,7 +2,7 @@ # SPDX-License-Identifier: Unlicense import std/[httpcore, options, parseutils, sets, streams, strutils, tables, times, uri] -import preserves, ../../syndicate, ../bags +import preserves, ../../syndicate, ../bags, ./timers import ../protocols/http import taps @@ -114,7 +114,7 @@ proc lenLine(chunk: Chunk): string = type Driver = ref object facet: Facet - ds: Cap + ds, timers: Cap bindings: Bag[Value] # cannot make a bag of HttpBinding, no `==` operator sequenceNumber: BiggestInt @@ -128,6 +128,7 @@ type req: HttpRequest stream: StringStream mode: HttpResponseKind + active: bool proc send[T: byte|char](ses: Session; data: openarray[T]) = ses.conn.send(addr data[0], data.len, endOfMessage = false) @@ -187,6 +188,7 @@ method message(e: Exchange; turn: var Turn; a: AssertionRef) = of HttpResponseKind.status: if e.mode == res.orKind: + e.active = true e.ses.conn.startBatch() e.stream.write( SupportedVersion, " ", res.status.code, " ", res.status.message, CRLF, @@ -239,10 +241,21 @@ proc service(turn: var Turn; exch: Exchange) = if handler.isNone: stop(turn) else: - publish(turn, handler.get, HttpContext( + let + cap = newCap(turn, exch) + ctx = publish(turn, handler.get, HttpContext( req: exch.req, - res: embed newCap(turn, exch), + res: embed cap, )) + const timeout = initDuration(seconds = 4) + after(turn, exch.ses.driver.timers, timeout) do (turn: var Turn): + if not exch.active: + var res = HttpResponse(orKind: HttpResponseKind.status) + res.status.code = 504 + res.status.message = "Binding timeout" + message(turn, cap, res) + res = HttpResponse(orKind: HttpResponseKind.done) + message(turn, cap, res) proc service(ses: Session) = ## Service a connection to an HTTP client. @@ -302,7 +315,8 @@ proc httpListen(turn: var Turn; driver: Driver; port: Port): Listener = listener proc httpDriver(turn: var Turn; ds: Cap) = - let driver = Driver(facet: turn.facet, ds: ds) + let driver = Driver(facet: turn.facet, ds: ds, timers: turn.newDataspace) + spawnTimerDriver(turn, driver.timers) during(turn, ds, HttpBinding?:{ 1: grab(),