How to get all path except the first part?

Hi! I’m using caddy as a URL shortener + search engine helper. Here’s my Caddyfile:

go.domain.example {
   map {http.request.uri.path.0} {engine} {
      d            duckduckgo.com/?q=
      g            www.google.com/search?q=
      default      none
   }
   @matchesEngine expression `{http.request.uri.path.1} != "" && {engine} != "none"`
   redir @matchesEngine https://{engine}{http.request.uri.path.1} 301

   map {http.request.uri.path.0} {shortlink} {
      cc           caddy.community
      y            www.youtube.com
      default      none
   }
   @matchesShortlink expression `{shortlink} != "none"`
   redir @matchesShortlink https://{shortlink}

   @fallback path_regexp path .(.*)
   redir @fallback https://www.google.com/search?q={re.path.1} 301
}

This works fine except when I use slashes in the query for search engines. For example, https://go.domain.example/g/foo/bar will search for foo only on Google, instead of foo/bar

How can I fix this?

I know I can extract the substring I want with regexes, but I’m afraid I can’t do that and use map at the same time.

Thanks!

Howdy @dnsfr, welcome to the Caddy community.

I wonder if you could just route your engine matcher to a uri strip_prefix {path.0} and then redir to {engine}{uri} instead? Probably a lot faster than a regex.

Quick test seems to indicate it should work exactly as expected:

~/Projects/caddy
➜ cat Caddyfile
http:// {
  uri strip_prefix {path.0}
  respond "{uri}"
}

~/Projects/caddy
➜ curl localhost/stuff/words/things
/words/things⏎
2 Likes

Hi, thank you for the reply, but I’m afraid that isn’t the intendend behavior.

For reference, here’s what I want to happen:

Huh? No, I mean literally route @matchesEngine instead of redir @matchesEngine and inside the route, strip the URI prefix.

It shouldn’t affect your /cc route at all? Unless I’m missing something.

My example above was purely to prove the concept.

1 Like

I still don’t fully understand what you mean, but I used a combo of handle + route + uri directives and I managed to get it working. Thanks!

2 Likes

Excellent!

Would you mind posting your working config? I’m curious to see how it ended up!

2 Likes

Here it is:


go.example.com {
   map {http.request.orig_uri.path.0} {engine} {
      d               duckduckgo.com/?q=
      y               www.youtube.com/results?search_query=
      default         none
   }
   @matchesEngine expression `{http.request.orig_uri.path.1} != "" && {engine} != "none"`
   handle @matchesEngine {
      route {
         uri path_regexp ^/[^/]+/ ""
         redir https://{engine}{uri} 301
      }
   }

   map {http.request.uri.path.0} {shortlink} {
      cc           caddy.community
      y            www.youtube.com
      default      none
   }
   @matchesShortlink expression `{shortlink} != "none"`
   handle @matchesShortlink {
      redir https://{shortlink}
   }

   @fallback path_regexp path ^/(.*)
   handle @fallback {
      redir https://www.google.com/search?q={re.path.1} 301
   }
}

Let me know if this can be simplified. But I tried a bunch of different combinations and none other worked.

In particular, the route directive made the uri path_regexp call work. Before it, the {uri} in the redir call was the same as the original one.

2 Likes

Yep - that’s because directives are evaluated in a specific order regardless of where they’re placed in the Caddyfile, by default: Caddyfile Directives — Caddy Documentation

The redir directive is normally processed before uri directives are. Using a route allows you to override the directive order, enabling URI manipulations to take place prior to the redirect.

Just two suggestions:

This can be a fast substring uri strip_prefix {path.0}/ instead of a more expensive regex manipulation.

This can also be handled slightly better. Ideally you don’t need to select for this matcher because the path will ALWAYS be some form of /*, but right now it looks like you’re using regex to get rid of the leading slash. You can just do this in another route with no matcher at all, again optimising away a regex operation:

  route {
    uri strip_prefix /
    redir https://www.google.com/search?q={uri} 301
  }

That’s pretty much all, though. The rest looks like a pretty well-formed Caddyfile to produce the specific set of results you’re after. I think it looks quite good.

4 Likes

This topic was automatically closed 30 days after the last reply. New replies are no longer allowed.