Skip to content

Commit 4bc3582

Browse files
committed
WIP: Migrate displayException calls
Drop the backtraces when the resulting string is used in HTTP response bodies.
1 parent a6ebfa1 commit 4bc3582

File tree

9 files changed

+41
-16
lines changed

9 files changed

+41
-16
lines changed
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
{-# LANGUAGE ImplicitParams #-}
2+
3+
module Network.Wai.Utilities.Exception where
4+
5+
import Control.Exception
6+
import Imports
7+
8+
-- | `displayException` with empty `ExceptionContext`
9+
--
10+
-- Starting with GHC 9.10, exceptions carry a context that contains backtraces.
11+
-- Displaying these is not always desired; e.g. for HTTP response bodies.
12+
displayExceptionNoBacktrace :: (Exception e) => e -> String
13+
displayExceptionNoBacktrace = trim . displayException . toException
14+
where
15+
trim = (dropWhileEnd isSpace) . (dropWhile isSpace)

libs/wai-utilities/wai-utilities.cabal

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,7 @@ library
6565
exposed-modules:
6666
Network.Wai.Utilities
6767
Network.Wai.Utilities.Error
68+
Network.Wai.Utilities.Exception
6869
Network.Wai.Utilities.Headers
6970
Network.Wai.Utilities.JSONResponse
7071
Network.Wai.Utilities.MockServer

libs/wire-api-federation/src/Wire/API/Federation/Error.hs

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
--
1515
-- You should have received a copy of the GNU Affero General Public License along
1616
-- with this program. If not, see <https://www.gnu.org/licenses/>.
17+
{-# LANGUAGE ImplicitParams #-}
1718

1819
-- | Map federation errors to client-facing errors.
1920
--
@@ -95,6 +96,7 @@ import Network.HTTP.Types.Status
9596
import Network.HTTP.Types.Status qualified as HTTP
9697
import Network.HTTP2.Client qualified as HTTP2
9798
import Network.Wai.Utilities.Error qualified as Wai
99+
import Network.Wai.Utilities.Exception
98100
import OpenSSL.Session (SomeSSLException)
99101
import Servant.Client
100102
import Wire.API.Error
@@ -227,21 +229,21 @@ federationRemoteHTTP2Error target path = \case
227229
( Wai.mkError
228230
unexpectedFederationResponseStatus
229231
"federation-http2-error"
230-
(LT.pack (displayException e))
232+
(LT.pack (displayExceptionNoBacktrace e))
231233
)
232234
& addErrData
233235
(FederatorClientTLSException e) ->
234236
( Wai.mkError
235237
(HTTP.mkStatus 525 "SSL Handshake Failure")
236238
"federation-tls-error"
237-
(LT.pack (displayException e))
239+
(LT.pack (displayExceptionNoBacktrace e))
238240
)
239241
& addErrData
240242
(FederatorClientConnectionError e) ->
241243
( Wai.mkError
242244
federatorConnectionRefusedStatus
243245
"federation-connection-refused"
244-
(LT.pack (displayException e))
246+
(LT.pack (displayExceptionNoBacktrace e))
245247
)
246248
& addErrData
247249
where
@@ -259,12 +261,12 @@ federationClientHTTP2Error (FederatorClientConnectionError e) =
259261
Wai.mkError
260262
HTTP.status500
261263
"federation-not-available"
262-
(LT.pack (displayException e))
264+
(LT.pack (displayExceptionNoBacktrace e))
263265
federationClientHTTP2Error e =
264266
Wai.mkError
265267
HTTP.status500
266268
"federation-local-error"
267-
(LT.pack (displayException e))
269+
(LT.pack (displayExceptionNoBacktrace e))
268270

269271
federationRemoteResponseError :: SrvTarget -> Text -> HTTP.Status -> LByteString -> Wai.Error
270272
federationRemoteResponseError target path status body =
@@ -310,7 +312,7 @@ federationServantErrorToWai (UnsupportedContentType mediaType res) =
310312
<> LT.pack (show mediaType)
311313
)
312314
federationServantErrorToWai (ConnectionError e) =
313-
federationUnavailable . T.pack . displayException $ e
315+
federationUnavailable . T.pack . displayExceptionNoBacktrace $ e
314316

315317
federationErrorContentType :: ResponseF a -> LT.Text
316318
federationErrorContentType =

libs/wire-api/src/Wire/API/MLS/Group/Serialisation.hs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ import Data.Text qualified as T
3636
import Data.Text.Encoding qualified as T
3737
import Data.UUID qualified as UUID
3838
import Imports
39+
import Network.Wai.Utilities.Exception
3940
import Web.HttpApiData (FromHttpApiData (parseHeader))
4041
import Wire.API.Conversation
4142
import Wire.API.MLS.Group
@@ -73,7 +74,7 @@ convToGroupId parts = GroupId . L.toStrict . runPut $ do
7374
groupIdToConv :: GroupId -> Either String GroupIdParts
7475
groupIdToConv gid = do
7576
(rem', _, (ct, conv, gen)) <- first (\(_, _, msg) -> msg) $ runGetOrFail readConv (L.fromStrict (unGroupId gid))
76-
domain <- first displayException . T.decodeUtf8' . L.toStrict $ rem'
77+
domain <- first displayExceptionNoBacktrace . T.decodeUtf8' . L.toStrict $ rem'
7778
pure
7879
GroupIdParts
7980
{ convType = toEnum $ fromIntegral ct,

services/brig/src/Brig/Provider/RPC.hs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
--
1515
-- You should have received a copy of the GNU Affero General Public License along
1616
-- with this program. If not, see <https://www.gnu.org/licenses/>.
17+
{-# LANGUAGE ImplicitParams #-}
1718

1819
-- | RPCs towards service providers.
1920
module Brig.Provider.RPC
@@ -46,6 +47,7 @@ import Imports
4647
import Network.HTTP.Client qualified as Http
4748
import Network.HTTP.Types.Method
4849
import Network.HTTP.Types.Status
50+
import Network.Wai.Utilities.Exception
4951
import Ssl.Util (withVerifiedSslConnection)
5052
import System.Logger.Class (MonadLogger, field, msg, val, (~~))
5153
import System.Logger.Class qualified as Log
@@ -98,7 +100,7 @@ createBot scon new = do
98100
extReq scon ["bots"]
99101
. method POST
100102
. Bilge.json new
101-
onExc ex = lift (extLogError scon ex) >> throwE (ServiceUnavailableWith $ displayException ex)
103+
onExc ex = lift (extLogError scon ex) >> throwE (ServiceUnavailableWith $ displayExceptionNoBacktrace ex)
102104

103105
extReq :: ServiceConn -> [ByteString] -> Request -> Request
104106
extReq scon ps =

services/galley/src/Galley/API/Federation.hs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,7 @@ import Galley.Types.Conversations.Members
6464
import Galley.Types.Conversations.One2One
6565
import Galley.Types.UserList (UserList (UserList))
6666
import Imports
67+
import Network.Wai.Utilities.Exception
6768
import Polysemy
6869
import Polysemy.Error
6970
import Polysemy.Input
@@ -330,7 +331,7 @@ leaveConversation requestingDomain lc = do
330331

331332
pure $ LeaveConversationResponse (Right ())
332333
where
333-
internalErr = InternalErrorWithDescription . LT.pack . displayException
334+
internalErr = InternalErrorWithDescription . LT.pack . displayExceptionNoBacktrace
334335

335336
-- FUTUREWORK: report errors to the originating backend
336337
-- FUTUREWORK: error handling for missing / mismatched clients

services/galley/src/Galley/Keys.hs

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ import Data.PEM
3838
import Data.Proxy
3939
import Data.X509
4040
import Imports
41+
import Network.Wai.Utilities.Exception
4142
import Wire.API.MLS.CipherSuite
4243
import Wire.API.MLS.Keys
4344

@@ -119,7 +120,7 @@ decodeEcdsaKeyPair bytes = do
119120
pem <- expectOne "private key" pems
120121
let content = pemContent pem
121122
-- parse outer pkcs8 container as BER
122-
asn1 <- first displayException (decodeASN1' BER content)
123+
asn1 <- first displayExceptionNoBacktrace (decodeASN1' BER content)
123124
(oid, key) <- case asn1 of
124125
[ Start Sequence,
125126
IntVal _version,
@@ -139,7 +140,7 @@ decodeEcdsaKeyPair bytes = do
139140
)
140141
$ guard (oid == curveOID @c)
141142
-- parse key bytestring as BER again, this should be in the format of rfc5915
142-
asn1' <- first displayException (decodeASN1' BER key)
143+
asn1' <- first displayExceptionNoBacktrace (decodeASN1' BER key)
143144
(privBS, pubBS) <- case asn1' of
144145
[ Start Sequence,
145146
IntVal _version,
@@ -151,10 +152,10 @@ decodeEcdsaKeyPair bytes = do
151152
] -> pure (priv, pub)
152153
_ -> Left "invalid ECDSA key format: expected rfc5915 private key format"
153154
priv <-
154-
first displayException . eitherCryptoError $
155+
first displayExceptionNoBacktrace . eitherCryptoError $
155156
ECDSA.decodePrivate curve privBS
156157
pub <-
157-
first displayException . eitherCryptoError $
158+
first displayExceptionNoBacktrace . eitherCryptoError $
158159
ECDSA.decodePublic curve pubBS
159160
pure (priv, pub)
160161

@@ -165,7 +166,7 @@ decodeEd25519PrivateKey bytes = do
165166
pems <- pemParseLBS bytes
166167
pem <- expectOne "private key" pems
167168
let content = pemContent pem
168-
asn1 <- first displayException (decodeASN1' BER content)
169+
asn1 <- first displayExceptionNoBacktrace (decodeASN1' BER content)
169170
(priv, remainder) <- fromASN1 asn1
170171
expectEmpty remainder
171172
case priv of

services/spar/src/Spar/Scim.hs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,7 @@ import qualified Data.Text as T
6767
import qualified Data.Text.Encoding as T
6868
import Data.Text.Encoding.Error
6969
import Imports
70+
import Network.Wai.Utilities.Exception
7071
import Polysemy
7172
import Polysemy.Error (Error, fromExceptionSem, runError, throw, try)
7273
import Polysemy.Input (Input)
@@ -157,7 +158,7 @@ apiScim =
157158
-- We caught an exception that's not a Spar exception at all. It is wrapped into
158159
-- Scim.serverError.
159160
throw . SAML.CustomError . SparScimError $
160-
Scim.serverError (T.pack (displayException someException))
161+
Scim.serverError (T.pack (displayExceptionNoBacktrace someException))
161162
Right (Left err@(SAML.CustomError (SparScimError _))) ->
162163
-- We caught a 'SparScimError' exception. It is left as-is.
163164
throw err

tools/stern/src/Stern/Intra.hs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,7 @@ import Network.HTTP.Types (urlEncode)
101101
import Network.HTTP.Types.Method
102102
import Network.HTTP.Types.Status hiding (statusCode, statusMessage)
103103
import Network.Wai.Utilities (Error (..), mkError)
104+
import Network.Wai.Utilities.Exception
104105
import Servant.API
105106
import Servant.Client qualified as SC
106107
import Servant.Server qualified as SS
@@ -1063,7 +1064,7 @@ runClientToHandler :: SC.ClientM a -> Handler a
10631064
runClientToHandler client = do
10641065
clientEnv <- asks (.brigServantClientEnv)
10651066
res <- liftIO $ SC.runClientM client clientEnv
1066-
either (throwE . mkError status400 "servant-client-error" . LT.pack . displayException) pure res
1067+
either (throwE . mkError status400 "servant-client-error" . LT.pack . displayExceptionNoBacktrace) pure res
10671068

10681069
domRegLock :: Domain -> SC.ClientM NoContent
10691070
domRegUnlock :: Domain -> SC.ClientM NoContent

0 commit comments

Comments
 (0)