From 3b3c14b77ecd3e7e4f3d3856e6108c45cc475280 Mon Sep 17 00:00:00 2001 From: Gabriel Gonzalez Date: Thu, 4 Oct 2018 07:23:17 -0700 Subject: [PATCH] Fix import chaining for custom header support (#618) Fixes https://github.com/dhall-lang/dhall-json/issues/60 In the above issue, a remote import specified custom headers using a relative path: ``` $ curl https://gist.githubusercontent.com/reactormonk/a8192fe784608f1f7515d5583c448095/raw/d46f5b9aea9eb56c4bdd92d187936ee87e9f4cf2/local.dhall let test = https://gist.githubusercontent.com/reactormonk/a8192fe784608f1f7515d5583c448095/raw/e8e5b14c2afe9acc342fe111bcf6e09b90dced9c/test.dhall using ./headers in test ``` But import chaining was not working correctly for the `using` clause of the import, meaning that before this change the `./headers` import was not anchored to the parent import. Using the `` judgment from the standard, the previous behavior was: ``` http://example0.com/foo http://example1.com/bar using ./baz = http://example1.com/bar using ./baz ``` ... when the behavior should have been: ``` http://example0.com/foo http://example1.com/bar using ./baz = http://example1.com/bar using http://example0.com/baz ``` Note that custom header support has not yet been fully standardized, but the latter version is what the correct behavior should be once it is standardized. The reason the former version is problematic is because it does not behave correctly in the presence of header forwarding. If `http://example1.com/bar` imports any remote expressions of its own, it will use the relative import `./baz` to customize the headers for downstream imports from the same domain. However, because this relative import is not anchored to the parent import, it will change for each downstream import. For example, suppose that the contents of `http://example1.com/bar using ./baz` are: ``` http://example1.com/baz ``` Import chaining that after its parent import would give: ``` http://example1.com/bar using ./baz http://example1.com/baz = http://example1.com/baz using ./baz ``` ... which introduces an inadvertent import cycle because now `./baz` will resolve to `http://example1.com/baz` instead of `http://example0.com/baz`. An import cycle similar to this one caused the bug described by the linked issue. This change fixes import chaining to correctly anchor custom header imports to the parent import and this fix resolves the above issue. This also includes a small change to fix canonicalization to also canonicalize the custom header import, although this is unrelated to the above bug. --- src/Dhall/Core.hs | 7 +++++++ src/Dhall/Import.hs | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/src/Dhall/Core.hs b/src/Dhall/Core.hs index f9e912c..0628427 100644 --- a/src/Dhall/Core.hs +++ b/src/Dhall/Core.hs @@ -190,6 +190,13 @@ instance Semigroup ImportType where Remote (URL { path = path₀, ..}) <> Local Here path₁ = Remote (URL { path = path₀ <> path₁, ..}) + import₀ <> Remote (URL { headers = headers₀, .. }) = + Remote (URL { headers = headers₁, .. }) + where + importHashed₀ = ImportHashed Nothing import₀ + + headers₁ = fmap (importHashed₀ <>) headers₀ + _ <> import₁ = import₁ diff --git a/src/Dhall/Import.hs b/src/Dhall/Import.hs index 37b427b..8227276 100644 --- a/src/Dhall/Import.hs +++ b/src/Dhall/Import.hs @@ -377,7 +377,7 @@ instance Canonicalize ImportType where Local prefix (canonicalize file) canonicalize (Remote (URL {..})) = - Remote (URL { path = canonicalize path, ..}) + Remote (URL { path = canonicalize path, headers = fmap canonicalize headers, ..}) canonicalize (Env name) = Env name