Closed audunhalland closed 5 years ago
I was able to solve this problem like this, not requiring any code change:
- com.df.setReqHeader=X-Forwarded-Prefix /y if { path_beg /y }
this can also be used together with reqPathSearchReplace
and it works. But it's not overwhelmingly ergonomic. Closing this for now as it's not strictly needed.
Hmm, I'm still thinking it would be a nice shorthand to be able to write e.g.
- com.df.servicePathMapping=/y,/
which would be roughly equivalent to:
- com.df.servicePath=/y
- com.df.setReqHeader=X-Forwarded-Prefix /y if { path_beg /y }
- com.df.reqPathSearchReplace=/y,/
So I'm reopening for people to comment on this proposal.
(note reqPathSearchReplace
ideally in this case should only strip from the beginning of the path)
Consider the following set of labels:
- com.df.servicePathMapping=/y,/
- com.df.servicePath=/y
- com.df.setReqHeader=X-Forwarded-Prefix /y if { path_beg /y }
- com.df.reqPathSearchReplace=/y,/z
where reqPathSearchReplace=/y,/z
conflicts with servicePathMapping=/y,/
. What do you think we should do in this situation?
As you say this looks like a conflict but I think it isn't. So if you use the imagined servicePathMapping
, the haproxy rules for backend would be placed before the setReqHeader
and reqPathSearchReplace
rules. Your if { path_beg /y }
would never trigger because path has already been stripped. The input to reqPathSearchReplace
would also be the pre-stripped path. Correct?
(Another problem with combining setReqHeader
and reqPathSearchReplace
like in my solution is that the order they are applied seems arbitrary, and someone might change the order in the future, breaking everything.)
Having the configuration depend on order is something I wish to avoid.
Another approach would be to ignore user defined servicePath
, setReqHeader
, and reqPathSearchReplace
, when servicePathMapping
is defined. Essentially, using servicePathMapping
reduces flexibly in exchange for ergonomics.
Ok, so that's a general problem with configuration values that ultimately expands to sequential code in some form.
It depends on what was the original purpose of setReqHeader
and reqPathSearchReplace
; are they intended to solve the exact thing that servicePathMapping
solves, or are there other use cases for them.
I can see setReqHeader
being used for other purposes. If a user just wants to only do service path mapping, they can use servicePathMapping
. If they need more control over the request header, they would need to fall back to the three labels.
I am still on the fence on adding servicePathMapping
since it can already be done in DFP. It all comes down to how easy we want the DFP api to be.
Yes, agree.
I have a service mapped to some DFP servicePath, say
/x
. This service also internally serves all its endpoints under/x
. It returns links to its own endpoints, which it is able to do thanks to HTTPHost
andX-Forwarded-Proto
headers.A problem arises if I want to expose the same service on different service paths. (real life example, under a different domain it's supposed to have a different service path). It's possible to get the proxy routing right using
reqPathSearchReplace
:If I call the service through
y.com/y
, its generated internal links end up beingy.com/x/foo
, because it has no idea about the path/search/replace that's going on in haproxy.There's a conventional HTTP header for dealing with this situation, named
X-Forwarded-Prefix
, I think of it as a "variable service path". At least https://github.com/spring-projects/spring-framework and a number of other web application frameworks support this header out of the box.So, for
reqPathSearchReplace
this will not be able to fly, because that rule can replace any part of the path and a prefix cannot be computed statically for haproxy config.A proposed way to be able to configure such a setup would be to use e.g.
servicePathMapping
or similar:in which case the service would still be serving internally under
/x
but an incomingX-Forwarded-Prefix
would kind-of overwrite that. (Request/y/foo
goes to/x/foo
withX-Forwarded-Prefix: /y
)or even simpler:
in which case the service would just be serving everything under root
/
.