Merge branch 'develop' into master

This commit is contained in:
Pyry Kovanen 2023-10-02 16:41:23 +03:00 committed by GitHub
commit d4068d4d68
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 188 additions and 77 deletions

View File

@ -764,6 +764,7 @@
:: Messaging Tasks :: Messaging Tasks
:: ::
:: %hear: packet from unix :: %hear: packet from unix
:: %dear: lane from unix
:: %heed: track peer's responsiveness; gives %clog if slow :: %heed: track peer's responsiveness; gives %clog if slow
:: %jilt: stop tracking peer's responsiveness :: %jilt: stop tracking peer's responsiveness
:: %cork: request to delete message flow :: %cork: request to delete message flow
@ -794,6 +795,7 @@
+$ task +$ task
$+ ames-task $+ ames-task
$% [%hear =lane =blob] $% [%hear =lane =blob]
[%dear =ship =lane]
[%heed =ship] [%heed =ship]
[%jilt =ship] [%jilt =ship]
[%cork =ship] [%cork =ship]

View File

@ -2119,6 +2119,27 @@
%^ enqueue-alien-todo ship ship-state %^ enqueue-alien-todo ship ship-state
|= todos=alien-agenda |= todos=alien-agenda
todos(heeds (~(del in heeds.todos) duct)) todos(heeds (~(del in heeds.todos) duct))
:: +on-dear: handle lane from unix
::
++ on-dear
|= [=ship =lane]
^+ event-core
?: ?=(%.y -.lane)
event-core
=/ ip=@if (end [0 32] p.lane)
=/ pt=@ud (cut 0 [32 16] p.lane)
?: =(%czar (clan:title ship))
%- %^ ev-trace odd.veb ship
|.("ignoring %dear lane {(scow %if ip)}:{(scow %ud pt)} for galaxy")
event-core
=/ peer-state=(unit peer-state) (get-peer-state ship)
?~ peer-state
%- %^ ev-trace odd.veb ship
|.("no peer-state for ship, ignoring %dear")
event-core
%- %^ ev-trace rcv.veb ship
|.("incoming %dear lane {(scow %if ip)}:{(scow %ud pt)}")
abet:(on-dear:(abed-peer:pe ship u.peer-state) lane)
:: +on-hear: handle raw packet receipt :: +on-hear: handle raw packet receipt
:: ::
++ on-hear ++ on-hear
@ -3312,6 +3333,11 @@
=. keens (~(put by keens) path *keen-state) =. keens (~(put by keens) path *keen-state)
fi-abet:(fi-start:(abed:fi path) duct) fi-abet:(fi-start:(abed:fi path) duct)
:: ::
++ on-dear
|= =lane
^+ peer-core
peer-core(route.peer-state `[%.y lane])
::
++ on-tame ++ on-tame
^+ peer-core ^+ peer-core
peer-core(route.peer-state ~) peer-core(route.peer-state ~)
@ -4973,6 +4999,7 @@
?- -.task ?- -.task
%born on-born:event-core %born on-born:event-core
%hear (on-hear:event-core [lane blob ~]:task) %hear (on-hear:event-core [lane blob ~]:task)
%dear (on-dear:event-core +.task)
%heed (on-heed:event-core ship.task) %heed (on-heed:event-core ship.task)
%init on-init:event-core %init on-init:event-core
%jilt (on-jilt:event-core ship.task) %jilt (on-jilt:event-core ship.task)

View File

@ -4315,8 +4315,12 @@
:- -:!>(*(map lobe page)) :- -:!>(*(map lobe page))
^- (map lobe page) ^- (map lobe page)
%- %~ rep in %- %~ rep in
%- reachable-takos |- ^- (set tako)
(~(got by hit.dom) let.dom) =/ ts=(set tako)
%- reachable-takos
(~(got by hit.dom) let.dom)
?: (lte let.dom 1) ts
(~(uni in ts) $(let.dom (dec let.dom)))
|= [t=tako o=(map lobe page)] |= [t=tako o=(map lobe page)]
%- ~(gas by o) %- ~(gas by o)
%+ turn %+ turn
@ -4533,7 +4537,12 @@
?. ?| =(0v0 tak) ?. ?| =(0v0 tak)
?& (~(has by hut.ran) tak) ?& (~(has by hut.ran) tak)
?| (~(any by hit.dom) |=(=tako =(tak tako))) :: fast-path ?| (~(any by hit.dom) |=(=tako =(tak tako))) :: fast-path
(~(has in (reachable-takos (aeon-to-tako:ze let.dom))) tak) |- ^- ?
?: (lte let.dom 1)
%.n
?| (~(has in (reachable-takos (aeon-to-tako:ze let.dom))) tak)
$(let.dom (dec let.dom))
==
== ==
|(?=(~ for) (may-read u.for care.mun tak path.mun)) |(?=(~ for) (may-read u.for care.mun tak path.mun))
== == == ==

View File

@ -789,8 +789,7 @@
%. (~(put by connections.state) duct connection) %. (~(put by connections.state) duct connection)
(trace 2 |.("{<duct>} creating local")) (trace 2 |.("{<duct>} creating local"))
:: ::
:_ state (request-to-app [%ours ~] app.act inbound-request.connection)
(subscribe-to-app [%ours ~] app.act inbound-request.connection)
:: +request: starts handling an inbound http request :: +request: starts handling an inbound http request
:: ::
++ request ++ request
@ -964,8 +963,7 @@
== ==
:: ::
%app %app
:_ state (request-to-app identity app.action inbound-request.connection)
(subscribe-to-app identity app.action inbound-request.connection)
:: ::
%authentication %authentication
(handle-request:authentication secure host address [suv identity] request) (handle-request:authentication secure host address [suv identity] request)
@ -1100,11 +1098,24 @@
%^ return-static-data-on-duct status 'text/html' %^ return-static-data-on-duct status 'text/html'
(error-page status authenticated url.request tape) (error-page status authenticated url.request tape)
-- --
:: +subscribe-to-app: subscribe to app and poke it with request data :: +request-to-app: subscribe to app and poke it with request data
:: ::
++ subscribe-to-app ++ request-to-app
|= [=identity app=term =inbound-request:eyre] |= [=identity app=term =inbound-request:eyre]
^- (list move) ^- (quip move server-state)
:: if the agent isn't running, we synchronously serve a 503
::
?. !<(? q:(need (need (rof ~ /eyre %gu [our app da+now] /$))))
%^ return-static-data-on-duct 503 'text/html'
%: error-page
503
?=(%ours -.identity)
url.request.inbound-request
"%{(trip app)} not running"
==
:: otherwise, subscribe to the agent and poke it with the request
::
:_ state
:~ %+ deal-as :~ %+ deal-as
/watch-response/[eyre-id] /watch-response/[eyre-id]
[identity our app %watch /http-response/[eyre-id]] [identity our app %watch /http-response/[eyre-id]]
@ -1347,14 +1358,15 @@
^- (unit @uv) ^- (unit @uv)
:: are there cookies passed with this request? :: are there cookies passed with this request?
:: ::
:: TODO: In HTTP2, the client is allowed to put multiple 'Cookie' =/ cookie-header=@t
:: headers. %+ roll header-list.request
|= [[key=@t value=@t] c=@t]
?. =(key 'cookie')
c
(cat 3 (cat 3 c ?~(c 0 '; ')) value)
:: is the cookie line valid?
:: ::
?~ cookie-header=(get-header:http 'cookie' header-list.request) ?~ cookies=(rush cookie-header cock:de-purl:html)
~
:: is the cookie line is valid?
::
?~ cookies=(rush u.cookie-header cock:de-purl:html)
~ ~
:: is there an urbauth cookie? :: is there an urbauth cookie?
:: ::
@ -2111,7 +2123,7 @@
duct-to-key.channel-state duct-to-key.channel-state
(~(del by duct-to-key.channel-state.state) duct) (~(del by duct-to-key.channel-state.state) duct)
== ==
:: +set-timeout-timer-for: sets a timeout timer on a channel :: +update-timeout-timer-for: sets a timeout timer on a channel
:: ::
:: This creates a channel if it doesn't exist, cancels existing timers :: This creates a channel if it doesn't exist, cancels existing timers
:: if they're already set (we cannot have duplicate timers), and (if :: if they're already set (we cannot have duplicate timers), and (if
@ -2185,53 +2197,76 @@
++ on-get-request ++ on-get-request
|= [channel-id=@t [session-id=@uv =identity] =request:http] |= [channel-id=@t [session-id=@uv =identity] =request:http]
^- [(list move) server-state] ^- [(list move) server-state]
:: if there's no channel-id, we must 404
::TODO but arm description says otherwise?
::
?~ maybe-channel=(~(get by session.channel-state.state) channel-id)
%^ return-static-data-on-duct 404 'text/html'
(error-page 404 | url.request ~)
:: find the channel creator's identity, make sure it matches
::
?. =(identity identity.u.maybe-channel)
%^ return-static-data-on-duct 403 'text/html'
(error-page 403 | url.request ~)
:: find the requested "mode" and make sure it doesn't conflict
::
=/ mode=?(%json %jam) =/ mode=?(%json %jam)
(find-channel-mode %'GET' header-list.request) (find-channel-mode %'GET' header-list.request)
?. =(mode mode.u.maybe-channel) =^ [exit=? =wall moves=(list move)] state
%^ return-static-data-on-duct 406 'text/html' :: the request may include a 'Last-Event-Id' header
=; msg=tape (error-page 406 %.y url.request msg) ::
"channel already established in {(trip mode.u.maybe-channel)} mode" =/ maybe-last-event-id=(unit @ud)
:: when opening an event-stream, we must cancel our timeout timer ?~ maybe-raw-header=(get-header:http 'last-event-id' header-list.request)
:: if there's no duct already bound. Else, kill the old request ~
:: and replace it (rush u.maybe-raw-header dum:ag)
:: :: if the channel doesn't exist yet, simply instantiate it here
=^ cancel-moves state ::
?. ?=([%| *] state.u.maybe-channel) ?~ maybe-channel=(~(get by session.channel-state.state) channel-id)
:_ state =- [[| ~ ~] state(session.channel-state -)]
(cancel-timeout-move channel-id p.state.u.maybe-channel)^~ %+ ~(put by session.channel-state.state) channel-id
=/ cancel-heartbeat ::NOTE some other fields initialized at the end of this arm
?~ heartbeat.u.maybe-channel ~ %* . *channel
:_ ~ identity identity
%+ cancel-heartbeat-move channel-id next-id (fall maybe-last-event-id 0)
[date duct]:u.heartbeat.u.maybe-channel last-ack now
=- [(weld cancel-heartbeat -<) ->] ==
(handle-response(duct p.state.u.maybe-channel) [%cancel ~]) :: if the channel does exist, we put some demands on the get request,
:: the request may include a 'Last-Event-Id' header :: and may need to do some cleanup for prior requests.
:: ::
=/ maybe-last-event-id=(unit @ud) :: find the channel creator's identity, make sure it matches
?~ maybe-raw-header=(get-header:http 'last-event-id' header-list.request) ::
~ ?. =(identity identity.u.maybe-channel)
(rush u.maybe-raw-header dum:ag) =^ mos state
:: flush events older than the passed in 'Last-Event-ID' %^ return-static-data-on-duct 403 'text/html'
:: (error-page 403 | url.request ~)
=? state ?=(^ maybe-last-event-id) [[& ~ mos] state]
(acknowledge-events channel-id u.maybe-last-event-id) :: make sure the request "mode" doesn't conflict with a prior request
:: combine the remaining queued events to send to the client ::
:: ::TODO or could we change that on the spot, given that only a single
=/ event-replay=wall :: request will ever be listening to this channel?
?. =(mode mode.u.maybe-channel)
=^ mos state
%^ return-static-data-on-duct 406 'text/html'
=; msg=tape (error-page 406 %.y url.request msg)
"channel already established in {(trip mode.u.maybe-channel)} mode"
[[& ~ mos] state]
:: when opening an event-stream, we must cancel our timeout timer
:: if there's no duct already bound. else, kill the old request,
:: we will replace its duct at the end of this arm
::
=^ cancel-moves state
?: ?=([%& *] state.u.maybe-channel)
:_ state
(cancel-timeout-move channel-id p.state.u.maybe-channel)^~
=. duct-to-key.channel-state.state
(~(del by duct-to-key.channel-state.state) p.state.u.maybe-channel)
=/ cancel-heartbeat
?~ heartbeat.u.maybe-channel ~
:_ ~
%+ cancel-heartbeat-move channel-id
[date duct]:u.heartbeat.u.maybe-channel
=- [(weld cancel-heartbeat -<) ->]
(handle-response(duct p.state.u.maybe-channel) [%cancel ~])
:: flush events older than the passed in 'Last-Event-ID'
::
=? state ?=(^ maybe-last-event-id)
(acknowledge-events channel-id u.maybe-last-event-id)
::TODO that did not remove them from the u.maybe-channel queue though!
:: we may want to account for maybe-last-event-id, for efficiency.
:: (the client _should_ ignore events it heard previously if we do
:: end up re-sending them, but _requiring_ that feels kinda risky)
::
:: combine the remaining queued events to send to the client
::
=; event-replay=wall
[[| - cancel-moves] state]
%- zing %- zing
%- flop %- flop
=/ queue events.u.maybe-channel =/ queue events.u.maybe-channel
@ -2249,6 +2284,7 @@
(channel-event-to-tape u.maybe-channel request-id channel-event) (channel-event-to-tape u.maybe-channel request-id channel-event)
?~ said $ ?~ said $
$(events [(event-tape-to-wall id +.u.said) events]) $(events [(event-tape-to-wall id +.u.said) events])
?: exit [moves state]
:: send the start event to the client :: send the start event to the client
:: ::
=^ http-moves state =^ http-moves state
@ -2259,7 +2295,7 @@
['cache-control' 'no-cache'] ['cache-control' 'no-cache']
['connection' 'keep-alive'] ['connection' 'keep-alive']
== ==
(wall-to-octs event-replay) (wall-to-octs wall)
complete=%.n complete=%.n
== ==
:: associate this duct with this session key :: associate this duct with this session key
@ -2289,7 +2325,7 @@
heartbeat (some [heartbeat-time duct]) heartbeat (some [heartbeat-time duct])
== ==
:: ::
[[heartbeat :(weld http-moves cancel-moves moves)] state] [[heartbeat :(weld http-moves moves)] state]
:: +acknowledge-events: removes events before :last-event-id on :channel-id :: +acknowledge-events: removes events before :last-event-id on :channel-id
:: ::
++ acknowledge-events ++ acknowledge-events
@ -2337,11 +2373,6 @@
?: ?=(%| -.maybe-requests) ?: ?=(%| -.maybe-requests)
%^ return-static-data-on-duct 400 'text/html' %^ return-static-data-on-duct 400 'text/html'
(error-page 400 & url.request (trip p.maybe-requests)) (error-page 400 & url.request (trip p.maybe-requests))
:: while weird, the request list could be empty
::
?: =(~ p.maybe-requests)
%^ return-static-data-on-duct 400 'text/html'
(error-page 400 %.y url.request "empty list of actions")
:: check for the existence of the channel-id :: check for the existence of the channel-id
:: ::
:: if we have no session, create a new one set to expire in :: if we have no session, create a new one set to expire in

View File

@ -12,7 +12,7 @@
++ parse-current-version ++ parse-current-version
|= current=vere |= current=vere
^- @t ^- @t
(rear rev.current) (slav %ta (rear rev.current))
:: ::
++ is-equal-version ++ is-equal-version
|= [latest=@t current=vere] |= [latest=@t current=vere]

View File

@ -262,7 +262,7 @@
== ==
:: ::
++ ex-channel-response ++ ex-channel-response
|= body=@t |= body=(unit @t)
|= mov=move |= mov=move
^- tang ^- tang
?. ?=([[[%http-blah ~] ~] %give %response %start * * %.n] mov) ?. ?=([[[%http-blah ~] ~] %give %response %start * * %.n] mov)
@ -273,7 +273,7 @@
['connection' 'keep-alive'] ['connection' 'keep-alive']
['set-cookie' cookie-string] ['set-cookie' cookie-string]
== ==
=/ body `(as-octs:mimes:html body) =/ body (bind body as-octs:mimes:html)
;: weld ;: weld
(expect-eq !>(200) !>(status-code.response-header.http-event.p.card.mov)) (expect-eq !>(200) !>(status-code.response-header.http-event.p.card.mov))
(expect-eq !>(body) !>(data.http-event.p.card.mov)) (expect-eq !>(body) !>(data.http-event.p.card.mov))
@ -375,6 +375,7 @@
|= [gang pov=path =view =beam] |= [gang pov=path =view =beam]
^- (unit (unit cage)) ^- (unit (unit cage))
?: =(%gd view) ``noun+!>(%base) ?: =(%gd view) ``noun+!>(%base)
?: =(%gu view) ``noun+!>(=(%app1 q.beam))
?: &(=(%ca view) =(/gen/handler/hoon s.beam)) ?: &(=(%ca view) =(/gen/handler/hoon s.beam))
:+ ~ ~ :+ ~ ~
vase+!>(!>(|=(* |=(* [[%404 ~] ~])))) vase+!>(!>(|=(* |=(* [[%404 ~] ~]))))
@ -553,6 +554,21 @@
(take /watch-response/[eyre-id] ~[/http-blah] sign) (take /watch-response/[eyre-id] ~[/http-blah] sign)
=/ headers ['content-type' 'text/html']~ =/ headers ['content-type' 'text/html']~
(expect-moves mos (ex-continue-response `[3 'ya!'] %.n) ~) (expect-moves mos (ex-continue-response `[3 'ya!'] %.n) ~)
::
++ test-dead-app-request
%- eval-mare
=/ m (mare ,~)
;< ~ bind:m perform-init-wo-timer
;< ~ bind:m (wait ~d1)
:: dead-app binds successfully
::
;< ~ bind:m (connect %dead-app /)
;< ~ bind:m (wait ~d1)
:: outside requests a path that dead-app has bound to
::
;< mos=(list move) bind:m (get '/' ~)
=/ body `(error-page:eyre-gate 503 %.n '/' "%dead-app not running")
(expect-moves mos (ex-response 503 ['content-type' 'text/html']~ body) ~)
:: tests an app redirecting to the login handler, which then receives a post :: tests an app redirecting to the login handler, which then receives a post
:: and redirects back to app :: and redirects back to app
:: ::
@ -727,6 +743,32 @@
=/ wire /channel/subscription/'0123456789abcdef'/1/~nul/two/~nul =/ wire /channel/subscription/'0123456789abcdef'/1/~nul/two/~nul
(expect-moves mos (ex-gall-deal wire ~nul %two %leave ~) ~) (expect-moves mos (ex-gall-deal wire ~nul %two %leave ~) ~)
:: ::
++ test-channel-open-with-get
%- eval-mare
=/ m (mare ,~)
;< ~ bind:m perform-init-wo-timer
;< ~ bind:m perform-born
;< ~ bind:m (wait ~d1)
;< ~ bind:m perform-authentication-2
;< mos=(list move) bind:m
(get '/~/channel/0123456789abcdef' cookie)
;< now=@da bind:m get-now
=/ mov-1 (ex-wait /channel/heartbeat/'0123456789abcdef' (add now ~s20))
=/ mov-2 (ex-channel-response ~)
(expect-moves mos mov-1 mov-2 ~)
::
++ test-channel-put-zero-requests
%- eval-mare
=/ m (mare ,~)
;< ~ bind:m perform-init-start-channel-2
;< ~ bind:m (wait ~m1)
;< mos=(list move) bind:m
(put '/~/channel/0123456789abcdef' cookie '[]')
=/ mov-1 ex-204
=/ mov-2 (ex-rest /channel/timeout/'0123456789abcdef' ~1111.1.2..12.00.00)
=/ mov-3 (ex-wait /channel/timeout/'0123456789abcdef' ~1111.1.2..12.01.00)
(expect-moves mos mov-1 mov-2 mov-3 ~)
::
++ test-channel-results-before-open ++ test-channel-results-before-open
%- eval-mare %- eval-mare
=/ m (mare ,~) =/ m (mare ,~)
@ -760,7 +802,7 @@
;< now=@da bind:m get-now ;< now=@da bind:m get-now
=/ mov-1 (ex-wait /channel/heartbeat/'0123456789abcdef' (add now ~s20)) =/ mov-1 (ex-wait /channel/heartbeat/'0123456789abcdef' (add now ~s20))
=/ mov-2 =/ mov-2
%- ex-channel-response %+ ex-channel-response ~
''' '''
id: 0 id: 0
data: {"ok":"ok","id":0,"response":"poke"} data: {"ok":"ok","id":0,"response":"poke"}
@ -904,7 +946,7 @@
;< now=@da bind:m get-now ;< now=@da bind:m get-now
=/ mov-1 (ex-wait /channel/heartbeat/'0123456789abcdef' (add now ~s20)) =/ mov-1 (ex-wait /channel/heartbeat/'0123456789abcdef' (add now ~s20))
=/ mov-2 =/ mov-2
%- ex-channel-response %+ ex-channel-response ~
''' '''
id: 0 id: 0
data: {"ok":"ok","id":0,"response":"poke"} data: {"ok":"ok","id":0,"response":"poke"}
@ -1006,7 +1048,7 @@
=/ heartbeat (add now ~s20) =/ heartbeat (add now ~s20)
=/ mov-1 (ex-wait /channel/heartbeat/'0123456789abcdef' heartbeat) =/ mov-1 (ex-wait /channel/heartbeat/'0123456789abcdef' heartbeat)
=/ mov-2 =/ mov-2
%- ex-channel-response %+ ex-channel-response ~
''' '''
id: 0 id: 0
data: {"ok":"ok","id":0,"response":"poke"} data: {"ok":"ok","id":0,"response":"poke"}
@ -1076,7 +1118,7 @@
=/ heartbeat (add now ~s20) =/ heartbeat (add now ~s20)
=/ mov-1 (ex-wait /channel/heartbeat/'0123456789abcdef' heartbeat) =/ mov-1 (ex-wait /channel/heartbeat/'0123456789abcdef' heartbeat)
=/ mov-2 =/ mov-2
%- ex-channel-response %+ ex-channel-response ~
''' '''
id: 2 id: 2
data: {"json":[1],"id":1,"response":"diff"} data: {"json":[1],"id":1,"response":"diff"}