-
Notifications
You must be signed in to change notification settings - Fork 198
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add redirections and URL rewrite features #1161
Comments
I realized
Considering #997 and #1003 I think we should be able to "detach" redirections (any frontend that doesn't forward) from clusters. Currently, any frontend that isn't attached to a cluster (doesn't have a cluster id) returns a 401. I think we could generalize this behavior, allowing "clusterless" frontends to returns 301, 302 and 401 depending on the new |
Here is the current state of the development branch:
Sozu's template system was extended, and its configuration was simplified. Listeners and clusters can define a The new redirection flow is as follows:
The templates a user can define are filled with the variables:
Here is an example config using templates and template forwarding: [[listeners]]
protocol = "http"
address = "0.0.0.0:8080"
answers = { "404" = "default_404.html", "503" = "default_503.html", "custom_200" = "default_200.html" }
[clusters.MyCluster]
protocol = "http"
answers = { "503" = "mycluser_503.html", "custom_200" = "mycluser_200.html" }
https_redirect = true
https_redirect_port = 8443
frontends = [
{
address = "0.0.0.0:8080",
hostname = "/(cdn[0-9]*)/.foo./(.*)/.com",
path = "/client/id_([0-9]*)/(.*)",
path_type = "REGEX",
redirect_scheme = "USE_HTTPS",
redirect_template = "custom_200",
rewrite_host = "client_$PATH[1].bar.$HOST[2].com",
rewrite_path = "/$PATH[2]?cdn=$HOST[1]",
rewrite_port = 8442,
}
] with the following
we can get the following response:
|
Currently, Sozu cannot rewrite URLs, and its only redirection capabilities are generating 401 Unauthorized on routes detached from a cluster and 301 Permanently Moved to redirect the whole HTTP traffic of a cluster to HTTPS.
I think redirection and URL rewriting should be orthogonal features that can be composed. The rewriting of a URL to pass it to the origin or redirect to it, should be expressed in the same way. Additionally, a redirection should be expressed in the same way whether the URL is rewritten or not.
URL Rewriting
Sozu already has "variable" domain and path matching. Domain can be:
foo.com
)*.foo.com
)/cdn[0-9]/.foo./.*/.com
)And a path can be:
/api
)/client/
)/client/id_[0-9]*/.*
)How to reuse this system for rewriting
When a URL matches a frontend, it would collect capture groups for the domain and the path separately. Regardless of the type of domain and path, the first group in each capture list is the complete domain and path respectively (akin to regex implicit group 0). The following groups would depend on the specific type:
From those group, a new URL could be written using a simple template system with two variable arrays
HOST
andPATH
:Redirection
Like URL rewriting I think redirection should be expressed at the frontend level. At the very least the redirection system should be able to mark a frontend as "Permanently Moved", generating a 301 unconditionally. "Temporary Moved" (generating a 302) could be added. 401 Unauthorized could also be specified on the frontends of named clusters. Expressing this is quite trivial, what is less is conditional redirection. I don't like the idea of creating a full DSL to allow the expression of complex routing decision-making. But it should be possible to at least express the need to redirect to HTTPS if the request is HTTP (since Sozu has already this feature).
For forwarded rewritten URLs, the
X-Forwarded-Port
header is already added. TheX-Forwarded-Host
header could also be added with the original hostname. Should this behavior be optional? Should it override an already existingX-Forwarded-Host
?Composition
In addition to hostname and path rewrite, method, scheme, and port could also be theoretically rewritten. I don't like the idea of rewriting the method, I don't see a good usage for forwarded requests, and it can't be expressed in a redirection. Rewriting the scheme is useful for redirecting HTTP requests to HTTPS, but only makes sense for redirections, forwarded requests are always in HTTP. Finally rewriting port could also be useful for redirections, and can be expressed for forwarded requests as well (even if I don't see a good use case for this).
Proposal
I propose to add to frontends the following options:
redirect
:FORWARD
,PERMANENT
,TEMPORARY
,FORCE_HTTPS
(default toFORWARD
)redirect_scheme
:USE_SAME
,USE_HTTP
,USE_HTTPS
(only valid if redirect isPERMANENT
orTEMPORARY
, default toUSE_SAME
)rewrite_host
:Option<String>
rewrite_path
:Option<String>
rewrite_port
:Option<u16>
The URL rewriting is split into host, path, and port. This enforces the fact that the scheme cannot be rewritten directly. The scheme can be rewritten only for redirections, conditionally using the
FORCE_HTTPS
, or unconditionally usingredirect_sheme
.The only conditional redirection is
FORCE_HTTPS
.Extension
Sozu may gain shortly authentication capabilities. I expect this feature to be orthogonal to rewriting and mutually exclusive with redirection. Failing authentication would return a 403 (and failing to provide authentication would return a 401). Rewriting would only occur on successful authentication and forwarded to the origin.
Limitations
Conditional redirection is limited by design, but It may be something we want to develop?
Sozu doesn't distinguish between path and query parameters, if a user wishes to rewrite/add/remove one, regexes might not be powerful enough to do so (the regex crate we use doesn't implement look-around and backreferences).
Matching, collecting groups, and rewriting the URLs may slow down the frontend lookup especially if regexes are overused. I don't think this is avoidable, but to mitigate this the matching will certainly only use regex find (which is faster than full capture) and perform a full capture on the single matching frontend and only if this frontend requires rewriting. Additionally, the regex crate we use ensures that the maximum complexity of find/capture is O(MxN) (with M the length of the haystack and N the length of the regex).
Example
The text was updated successfully, but these errors were encountered: