fix laziness problem in git relaying

The switch to hGetMetered subtly changed the laziness of how DATA was
read, and broke git protocol relaying. Fix by sending received data to
the git process's stdin immediately, which ensures that the lazy
bytestring is all read from the peer before going on to process the next
message from the peer.
This commit is contained in:
Joey Hess 2016-12-08 15:15:29 -04:00
parent e56506d83c
commit c05f4eb631
No known key found for this signature in database
GPG key ID: C910D9222512E3C7

View file

@ -167,7 +167,7 @@ runRelay runner (RelayHandle hout) (RelayHandle hin) = bracket setup cleanup go
where where
setup = do setup = do
v <- newEmptyMVar v <- newEmptyMVar
void $ async $ relayFeeder runner v void $ async $ relayFeeder runner v hin
void $ async $ relayReader v hout void $ async $ relayReader v hout
return v return v
@ -175,7 +175,7 @@ runRelay runner (RelayHandle hout) (RelayHandle hin) = bracket setup cleanup go
hClose hin hClose hin
hClose hout hClose hout
go v = relayHelper runner v hin go v = relayHelper runner v
runRelayService :: P2PConnection -> RunProto IO -> Service -> IO (Maybe ()) runRelayService :: P2PConnection -> RunProto IO -> Service -> IO (Maybe ())
runRelayService conn runner service = bracket setup cleanup go runRelayService conn runner service = bracket setup cleanup go
@ -195,7 +195,7 @@ runRelayService conn runner service = bracket setup cleanup go
, std_in = CreatePipe , std_in = CreatePipe
} }
v <- newEmptyMVar v <- newEmptyMVar
void $ async $ relayFeeder runner v void $ async $ relayFeeder runner v hin
void $ async $ relayReader v hout void $ async $ relayReader v hout
waiter <- async $ waitexit v pid waiter <- async $ waitexit v pid
return (v, waiter, hin, hout, pid) return (v, waiter, hin, hout, pid)
@ -206,8 +206,8 @@ runRelayService conn runner service = bracket setup cleanup go
cancel waiter cancel waiter
void $ waitForProcess pid void $ waitForProcess pid
go (v, _, hin, _, _) = do go (v, _, _, _, _) = do
r <- relayHelper runner v hin r <- relayHelper runner v
case r of case r of
Nothing -> return Nothing Nothing -> return Nothing
Just exitcode -> runner $ net $ relayToPeer (RelayDone exitcode) Just exitcode -> runner $ net $ relayToPeer (RelayDone exitcode)
@ -215,16 +215,12 @@ runRelayService conn runner service = bracket setup cleanup go
waitexit v pid = putMVar v . RelayDone =<< waitForProcess pid waitexit v pid = putMVar v . RelayDone =<< waitForProcess pid
-- Processes RelayData as it is put into the MVar. -- Processes RelayData as it is put into the MVar.
relayHelper :: RunProto IO -> MVar RelayData -> Handle -> IO (Maybe ExitCode) relayHelper :: RunProto IO -> MVar RelayData -> IO (Maybe ExitCode)
relayHelper runner v hin = loop relayHelper runner v = loop
where where
loop = do loop = do
d <- takeMVar v d <- takeMVar v
case d of case d of
RelayFromPeer b -> do
L.hPut hin b
hFlush hin
loop
RelayToPeer b -> do RelayToPeer b -> do
r <- runner $ net $ relayToPeer (RelayToPeer b) r <- runner $ net $ relayToPeer (RelayToPeer b)
case r of case r of
@ -233,21 +229,25 @@ relayHelper runner v hin = loop
RelayDone exitcode -> do RelayDone exitcode -> do
_ <- runner $ net $ relayToPeer (RelayDone exitcode) _ <- runner $ net $ relayToPeer (RelayDone exitcode)
return (Just exitcode) return (Just exitcode)
RelayFromPeer _ -> loop -- not handled here
-- Takes input from the peer, and puts it into the MVar for processing. -- Takes input from the peer, and sends it to the relay process's stdin.
-- Repeats until the peer tells it it's done or hangs up. -- Repeats until the peer tells it it's done or hangs up.
relayFeeder :: RunProto IO -> MVar RelayData -> IO () relayFeeder :: RunProto IO -> MVar RelayData -> Handle -> IO ()
relayFeeder runner v = loop relayFeeder runner v hin = loop
where where
loop = do loop = do
mrd <- runner $ net relayFromPeer mrd <- runner $ net relayFromPeer
case mrd of case mrd of
Nothing -> putMVar v (RelayDone (ExitFailure 1)) Nothing ->
Just rd -> do putMVar v (RelayDone (ExitFailure 1))
putMVar v rd Just (RelayDone exitcode) ->
case rd of putMVar v (RelayDone exitcode)
RelayDone _ -> return () Just (RelayFromPeer b) -> do
_ -> loop L.hPut hin b
hFlush hin
loop
Just (RelayToPeer _) -> loop -- not handled here
-- Reads input from the Handle and puts it into the MVar for relaying to -- Reads input from the Handle and puts it into the MVar for relaying to
-- the peer. Continues until EOF on the Handle. -- the peer. Continues until EOF on the Handle.