From 55e43bf6c83892ff7d4dad4c3c8c03e5ad2fa797 Mon Sep 17 00:00:00 2001 From: steve-chavez Date: Fri, 29 Sep 2023 17:55:56 -0300 Subject: [PATCH] fix: incorrect parsing 4 fallback_application_name --- CHANGELOG.md | 1 + nix/README.md | 10 +++++++++- src/PostgREST/Config.hs | 31 +++++++++++++++++++++---------- 3 files changed, 31 insertions(+), 11 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c5e0585599..91d149cb78 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -25,6 +25,7 @@ This project adheres to [Semantic Versioning](http://semver.org/). - #2846, Fix error when requesting `Prefer: count=` and doing null filtering on embedded resources - @laurenceisla - #2959, Fix setting `default_transaction_isolation` unnecessarily - @steve-chavez - #2929, Fix arrow filtering on RPC returning dynamic TABLE with composite type - @steve-chavez + - #2970, Fix incorrect URI parsing for adding `fallback_application_name` - @steve-chavez ## [11.2.0] - 2023-08-10 diff --git a/nix/README.md b/nix/README.md index 33fae433d2..7d5bcbd955 100644 --- a/nix/README.md +++ b/nix/README.md @@ -13,7 +13,6 @@ To build PostgREST from your local checkout of the repository, run: ```bash $ nix-build --attr postgrestPackage - ``` This will create a `result` directory that contains the PostgREST binary at @@ -22,6 +21,15 @@ build the `postgrestPackage` attribute from the Nix expression it finds in our `default.nix` (see below for details). Nix will take care of getting the right GHC version and all the build dependencies. +You can also build a statically linked binary with: + +```bash +$ nix-build --attr postgrestStatic + +$ ldd result/bin/postgrest +$ not a dynamic executable +``` + ## Binary cache We recommend that you use the PostgREST binary cache on diff --git a/src/PostgREST/Config.hs b/src/PostgREST/Config.hs index 47f4e99abe..2520b1af71 100644 --- a/src/PostgREST/Config.hs +++ b/src/PostgREST/Config.hs @@ -49,8 +49,7 @@ import Data.List.NonEmpty (fromList, toList) import Data.Maybe (fromJust) import Data.Scientific (floatingOrInteger) import Network.URI (escapeURIString, - isUnescapedInURIComponent, parseURI, - uriQuery) + isUnescapedInURIComponent) import Numeric (readOct, showOct) import System.Environment (getEnvironment) import System.Posix.Types (FileMode) @@ -472,6 +471,8 @@ readPGRSTEnvironment = M.map T.pack . M.fromList . filter (isPrefixOf "PGRST_" . fst) <$> getEnvironment -- | Adds a `fallback_application_name` value to the connection string. This allows querying the PostgREST version on pg_stat_activity. +-- | This follows the same logic as libpq for parsing the URI https://github.com/postgres/postgres/blob/a829b704015104f49a11ea007957ef03a03dc0d4/src/interfaces/libpq/fe-connect.c#L5880-L5921 +-- | If there's a postgres URI scheme designator prefix ("postgres://") then the connstring is considered an URI, if not, it's in key/value format. -- -- >>> let ver = "11.1.0 (5a04ec7)"::ByteString -- >>> let strangeVer = "11'1&0@#$%,.:\"[]{}?+^()=asdfqwer"::ByteString @@ -496,15 +497,25 @@ readPGRSTEnvironment = -- -- >>> addFallbackAppName strangeVer "postgres:///postgres?host=server&port=5432" -- "postgres:///postgres?host=server&port=5432&fallback_application_name=PostgREST%2011%271%260%40%23%24%25%2C.%3A%22%5B%5D%7B%7D%3F%2B%5E%28%29%3Dasdfqwer" +-- +-- Special chars in password +-- >>> addFallbackAppName ver "postgres:///postgres:pass=()[]&#?host=server&port=5432" +-- "postgres:///postgres:pass=()[]&#?host=server&port=5432&fallback_application_name=PostgREST%2011.1.0%20%285a04ec7%29" addFallbackAppName :: ByteString -> Text -> Text addFallbackAppName version dbUri = dbUri <> - case uriQuery <$> parseURI (toS dbUri) of - Nothing -> " " <> keyValFmt -- Assume key/value connection string if the uri is not valid - Just "" -> "?" <> uriFmt - Just "?" -> uriFmt - _ -> "&" <> uriFmt + if isPgURI dbUri + then case snd $ T.breakOn "?" dbUri of + "?" -> fallbackUriFmt + "" -> "?" <> fallbackUriFmt + _ -> "&" <> fallbackUriFmt + else " " <> fallbackKeyValFmt where - uriFmt = pKeyWord <> toS (escapeURIString isUnescapedInURIComponent $ toS pgrstVer) - keyValFmt = pKeyWord <> "'" <> T.replace "'" "\\'" pgrstVer <> "'" - pKeyWord = "fallback_application_name=" + fallbackUriFmt = key <> toS (escapeURIString isUnescapedInURIComponent $ toS pgrstVer) + fallbackKeyValFmt = key <> "'" <> T.replace "'" "\\'" pgrstVer <> "'" + key = "fallback_application_name=" pgrstVer = "PostgREST " <> T.decodeUtf8 version + isPgURI str = + let + uriDesignator = "postgresql://" + shortUriDesignator = "postgres://" in + uriDesignator `T.isPrefixOf` str || shortUriDesignator `T.isPrefixOf` str