diff --git a/README.md b/README.md
index be16225..d19c81d 100644
--- a/README.md
+++ b/README.md
@@ -30,6 +30,20 @@ https://udl.fdo.cr/?r=https://reservation.com/restaurants/silvestre
This will bypass the limitation of Safari (embedded webview) that doesn't allow your Universal Links to trigger. You should now have a working "open in app" UX.
+### Default destination support
+If the `DEFAULT_DESTINATION` environment variable is set and no `r` query parameter is provided:
+
+- A request to the root path:
+
+ - `https://udl.fdo.cr/` will redirect to `DEFAULT_DESTINATION`
+
+- A request with a path:
+
+ - `https://udl.fdo.cr/restaurants/silvestre` will redirect to `DEFAULT_DESTINATION + "/restaurants/silvestre"`
+
+The original `?r=` format continues to work as before. If `DEFAULT_DESTINATION` is not set, behavior remains unchanged.
+
+
`https://udl.fdo.cr` is a **public (free to use) UDL Server** instance for anyone to try out and use on your own. It has usage limits (throttling), which should be more than enough for most low-medium traffic websites.
If this service adds value to you or your company please consider sponsoring me right here on GitHub. I offer different sponsor tiers too where I will host a private instance without usage limits for ensured reliability. [Read more about this on my profile](https://github.com/sponsors/fdocr) to support the OSS work I do on my free time.
diff --git a/spec/server_spec.cr b/spec/server_spec.cr
index bd0531c..d28a393 100644
--- a/spec/server_spec.cr
+++ b/spec/server_spec.cr
@@ -1,5 +1,25 @@
require "./spec_helper"
+def with_default_destination(value)
+ original = ENV["DEFAULT_DESTINATION"]?
+ ENV["DEFAULT_DESTINATION"] = value
+ yield
+ensure
+ if original
+ ENV["DEFAULT_DESTINATION"] = original
+ else
+ ENV.delete("DEFAULT_DESTINATION")
+ end
+end
+
+def without_default_destination
+ original = ENV["DEFAULT_DESTINATION"]?
+ ENV.delete("DEFAULT_DESTINATION")
+ yield
+ensure
+ ENV["DEFAULT_DESTINATION"] = original if original
+end
+
describe "UDL Server" do
context "success" do
it "redirects to the Target URI parameter if valid" do
@@ -16,6 +36,24 @@ describe "UDL Server" do
response.headers["Location"].should eq(target_url)
end
+ it "redirects to DEFAULT_DESTINATION when root path has no r parameter and DEFAULT_DESTINATION is set" do
+ with_default_destination("https://example.com") do
+ get "/"
+
+ response.status_code.should eq(302)
+ response.headers["Location"].should eq("https://example.com")
+ end
+ end
+
+ it "redirects to DEFAULT_DESTINATION + path when path has no r parameter and DEFAULT_DESTINATION is set" do
+ with_default_destination("https://example.com") do
+ get "/about"
+
+ response.status_code.should eq(302)
+ response.headers["Location"].should eq("https://example.com/about")
+ end
+ end
+
it "populates apple-app-site-association file" do
get "/.well-known/apple-app-site-association"
@@ -26,20 +64,24 @@ describe "UDL Server" do
end
context "failure" do
- it "renders fallback page if target redirect not provided" do
- get "/"
+ it "renders fallback page if target redirect not provided and DEFAULT_DESTINATION is not set" do
+ without_default_destination do
+ get "/"
- response.status_code.should eq(200)
- response.body.should contain("Something went wrong")
- response.body.should contain("Check out the README for more details")
+ response.status_code.should eq(200)
+ response.body.should contain("Something went wrong")
+ response.body.should contain("Check out the README for more details")
+ end
end
- it "renders fallback page if requesting any other path" do
- get "/about-us"
+ it "renders fallback page if requesting any other path and DEFAULT_DESTINATION is not set" do
+ without_default_destination do
+ get "/about-us"
- response.status_code.should eq(200)
- response.body.should contain("Something went wrong")
- response.body.should contain("Check out the README for more details")
+ response.status_code.should eq(200)
+ response.body.should contain("Something went wrong")
+ response.body.should contain("Check out the README for more details")
+ end
end
it "renders fallback page if r parameter is an invalid URL" do
diff --git a/src/server.cr b/src/server.cr
index f4cae00..f8e53e3 100644
--- a/src/server.cr
+++ b/src/server.cr
@@ -13,7 +13,19 @@ error_context = "Use the root path instead, i.e. `/?r=TARGET_URL_HERE`"
get "/" do |env|
begin
- target_uri = URI.parse(env.params.query["r"])
+ redirect_param = env.params.query["r"]?
+
+ # If no r parameter, redirect to DEFAULT_DESTINATION (only if set)
+ unless redirect_param
+ if default_destination = ENV["DEFAULT_DESTINATION"]?
+ env.redirect default_destination
+ next
+ else
+ raise "Missing redirect parameter"
+ end
+ end
+
+ target_uri = URI.parse(redirect_param)
# Check that it's a valid URL
valid_uri = /https?/ =~ target_uri.scheme && target_uri.host
@@ -48,8 +60,15 @@ get "/.well-known/apple-app-site-association" do |env|
end
get "/*" do |env|
- udl_error = "Invalid path `#{env.request.path}` - #{error_context}"
- render "src/views/fallback.ecr"
+ # If DEFAULT_DESTINATION is set, redirect to it + path; otherwise show fallback.
+ if default_target = ENV["DEFAULT_DESTINATION"]?
+ path = env.request.path
+ final_url = default_target.rstrip("/") + "/" + path.lstrip("/")
+ env.redirect final_url
+ else
+ udl_error = "Invalid path `#{env.request.path}` - #{error_context}"
+ render "src/views/fallback.ecr"
+ end
end
error 404 do