Order of Jetty rewrite rules - url-rewriting

I'm working with some simple Jetty rewrite rules
<Configure id="FileServer" class="org.eclipse.jetty.server.Server">
<Get id="oldhandler" name="handler"/>
<Set name="handler">
<New id="Rewrite" class="org.eclipse.jetty.rewrite.handler.RewriteHandler">
<Set name="handler"><Ref id="oldhandler"/></Set>
<Call name="addRule">
<Arg>
<New class="org.eclipse.jetty.rewrite.handler.RewriteRegexRule">
<Set name="regex">/fake-uri/(.*)</Set>
<Set name="replacement">/real-uri/$1</Set>
</New>
</Arg>
</Call>
<Call name="addRule">
<Arg>
<New class="org.eclipse.jetty.rewrite.handler.HeaderPatternRule">
<Set name="pattern">/real-uri/*</Set>
<Set name="name">Cache-Control</Set>
<Set name="value">no-cache,no-store</Set>
</New>
</Arg>
</Call>
</New>
</Set>
</Configure>
If I request /fake-uri/index.html in the browser, the response contains what would be served by /real-uri/index.html and applies the Cache-Control headers. However, if I reorder the rules so the header rule is above the regex rule, the Cache-Control headers are absent for requests to /fake-uri/index.html.
Seems like order is important here, but I'm trying to workout what's happening. According to the doc
HeaderPatternRule - adds/modifies the HTTP headers in response
I'm unsure what the default is, but I've tried
<Set name="rewriteRequestURI">true</Set>
on the handler.
It doesn't seem to change anything, but I'd think if the request URI were rewritten, it wouldn't matter where the URI rewrite rule appeared in relation to a header rewrite which applies to output headers. Thing is even with rewriteRequestURI set to true, the header rule has to come second for the desired effect. So why is order important when I've set rewriteRequestURI?

The processing order is top-down and the rule engine continues to process rules until a rule terminates the processing.
Even though the HeaderPatternRule updates the Response it matches the URL on the Request. This is why the Cache-Control only is added if the order is such that the URL first is re-written to match the second rule.
The other part of your question about the following parameter:
<Set name="rewriteRequestURI">true</Set>
Doesn't really apply to what you are trying to do. The rewriteRequestURI parameter tells the rewrite engine to also update the HttpServletRequest.getRequestURI() like you said, but this doesn't affect the rule engine, but only how the Servlet applications are affected by the rewrites.
All that matters in the rule engine is ordering and if any rule terminates the processing with the statement:
<Set name="terminating">true</Set>
That would stop the rule engine.
One confusing note is if you use Redirect rules instead of the Rewrite rules. That would trigger the rule engine to be executed again on the Redirect. That way you can re-process rules from the beginning again (and create infinite loops)

Related

Sending chunked requests using Tsung

Does anybody know how to send POST requests with 'Transfer-Encoding' set to 'chunked' in Tsung? Do I just set the header in my request?
If so, will Tsung automatically chunk the requests? Is the chunk size configurable?
Also is there some method to disable the "Content-Length" header? My application expects only one of Content-Length or Transfer-Encoding, not both.
EDIT:
Sorry, I should have provided some sample code. Here is the Tsung snippet I used:
<request subst="true">
<http url="/blah/blah" method="POST" contents="{ "source_ip": "%%_requestip%%", "source_port": "%%_requestport%%", "method": "%%_method%%", "url":"%%_myurl%%", "http_version":"1.1","user_info":[{"username":"%%_myusername%%","client_id": "%%_myclientid%%"}],"headers":[{"host": "%%_apiid%%"},{"Authorization":"Bearer %%_mytoken%%"},{"x-api-key":"%%_myapikey%%"},%%_myheaderid%%]}">
<http_header name="Head123" value="approxyhttpjkjdalsjdjasldjasldjlasjldjasdkjasljdlasjd"/>
<http_header name="Transfer-Encoding" value="chunked"/>
<http_header name="X-CorrelationID" value="Id-%%_requestid%%" />
<http_header name="Content-Type" value="application/text"/>
</http>
</request>
As shown above, I am setting a 'Transfer-Encoding' header in my request.
I have two requirements.
How do I tell Tsung to send chunked packets? Is it by setting the 'Transfer-Encoding: chunked' header?
How do I tell Tsung to NOT send a 'Content-Length' header in a POST request? My application cannot handle both Transfer-Encoding and Content-Length, it needs one or the other.
You can just override the header, see Doc's Changelog:
12.2.2. Changed
[TSUN-307] - Allow all HTTP headers to be overridden by
Read the Doc's, 6.2.2 HTTP:
New in 1.2.2: You can add any HTTP header now, as in:
<request> <http url="/bla" method="POST" contents="bla=blu&name=glop"> <www_authenticate userid="Aladdin" passwd="open sesame"/> <http_header name="Cache-Control" value="no-cache"/> <http_header name="Referer" value="http://www.w3.org/"/> </http> </request>

'redirect' and 'proxy' vs 'forward' and 'passthrough' in Tuckey URLRewrite

Note that, in my attempt to display code examples, I will redact/edit out any references to the company for whom I work in an effort to obscure their identity, not so much to hide the fact that I'm even asking. It should also be of note that I am very new to this game of UrlRewrite/Tuckey/dotCMS.
I have been having trouble getting a redirect to work. It's using Tuckey URLRewrite through dotCMS. The attempt is to redirect, but as a forward versus a proxy, for SEO purposes.
I've found that the following works ('redirect' and 'proxy' are interchangeable here):
<to type="proxy">http://[redacted]:8080$1$3?%{query-string}</to>
However, the following leads to a 404 ('forward' and 'passthrough' are interchangeable here):
<to type="forward">http://[redacted]:8080$1$3?%{query-string}</to>
The entirety of the rule is as follows:
<!-- EN with Query Params -->
<rule>
<from>^/([^/]+)/en/([^/]+)?$</from>
<to type="proxy" qsappend="true">[redacted]:8080$1$3&%{query-string}</to>
</rule>
<!-- EN without Query Params -->
<rule>
<from>^(.*)(\/en)(\/.*)?$</from>
<to type="proxy">[redacted]:8080$1$3?%{query-string}</to>
</rule>
Some of my initial questions (as many more are likely to arise):
Is there such a difference between 'proxy'/'redirect' and 'forward'/'passthrough' that more specialized efforts to achieve a meaningful redirect need to be implemented?
Am I missing something in other configuration files that may affect the outcomes of these attempts at redirection?
EDIT: The differences in RegEx are me trying things to see if that could possibly be where the disconnect is occurring
Because urls in dotCMS do not really exist, the servlet requestdispatcher, which is used by forward rules, does not work. You need to set a request attribute, CMS_FILTER_URLMAP_OVERRIDE, which dotCMS will respect. In code, this looks like:
NormalRule forwardRule = new NormalRule();
forwardRule.setFrom( "^/example/forwardDotCMS/(.*)$" );
SetAttribute attribute = new SetAttribute();
attribute.setName("CMS_FILTER_URLMAP_OVERRIDE");
attribute.setValue("/about-us/index");
forwardRule.addSetAttribute(attribute);
addRewriteRule( forwardRule );

Translating .htaccess to Tuckey UrlRewriteFilter

I'm building a project using Spring Boot and Angular 1.5.X and I am struggling to handle full page refreshes of Angular routes - typical "404 because the path I made doesn't actually exist" problem. I've done a fair bit of research and the solution that I keep seeing is to implement a .htaccess file with the following snippet in order to redirect all unknown requests back to the index (I pulled the following from this post)
RewriteEngine On
Options FollowSymLinks
RewriteBase /
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)$ /#/$1 [L]
I have Tuckey's UrlRewriteFilter installed - according to this blog post since I don't have a WEB-INF folder - and it is working. It starts and it reads the urlrewrite.xml successfully. However, I don't know what to put in my urlrewrite.xml - I haven't the slightest clue of how to translate the above into something that the UrlRewriteFilter can understand. I've browsed the manual for the UrlRewriteFilter and I don't really know where / how to start.
Basically, what do I have to put in my urlrewrite.xml so that if I hit F5, my website doesn't puke back 404 errors?
Any help is appreciated.
Edit 1
I should mention that all of my API endpoints are prefaced with /api/** in order to distinguish them from links on my front end - an example would be /api/open/getUser and /api/secured/updateSettings.
Edit 2
Couple things I've discovered so far. One is that the UrlRewriteFilter can actually support .htaccess files and I did get it (as far as I can tell) to load in by moving the .htacess into my Resources folder and tweaking the code sample in the above blog post slightly, changing this
private static final String CONFIG_LOCATION = "classpath:/urlrewrite.xml";
to
private static final String CONFIG_LOCATION = "classpath:/.htaccess";
and
Conf conf = new Conf(filterConfig.getServletContext(), resource.getInputStream(), resource.getFilename(), "MyProject");
to
Conf conf = new Conf(filterConfig.getServletContext(), resource.getInputStream(), resource.getFilename(), "MyProject", true);
The addition of the true tells the filter to use a .htaccess file. Awesome, problem solved right? Not quite - it's hard to explain but it doesn't seem like the UrlRewriteFilter was/is reading the .htacess correctly. I was using an .htacess tester to verify that the regex's and rewrite conditions were working as I expected and they seemed to be. The tester said that they were fine. However, the UrlRewriteFilter would freak out and get stuck in some kind of loop, to the point that Java would throw a stack overflow exception (as to why, I've no idea - I can't seem to find a way to set the filter's logging level to debug via Java D:< ).
So clearly that didn't work - I am currently attempting to translate the .htaccess into urlrewrite.xml myself, and here is what I've managed to created so far.
<urlrewrite use-query-string="true">
<rule match-type="regex" enabled="true">
<note>
Any URI that ends with one of the following extensions will be allowed to continue on unimpeded.
Buried in the manual was the single line that said a "-" in the "to" will allow the request to
continue on unmodified.
</note>
<from>\.(html|css|jpeg|gif|png|js|ico|txt|pdf)$</from>
<to last="true">-</to>
</rule>
<rule match-type="regex" enabled="true">
<note>
Any URI that is prefaced with "/api/open/**" or "/api/secured/**" will be allowed through unmodified.
</note>
<condition type="request-uri" operator="equal">\/api\/(open|secured)\/([a-zA-Z0-9\/]+)</condition>
<from>^.*$</from>
<to last="true">-</to>
</rule>
<rule match-type="regex" enabled="false">
<note>
This one is supposed to be a "when all else fail" rule - if the other two rules don't match,
forward to the index and let Angular figure out the rest.
!! This one seems to be getting stuck in a loop of sorts !!
</note>
<from>^.*$</from>
<to last="true">/</to>
</rule>
</urlrewrite>
The first two seem to be working splendidly. The third rule (the one with enabled set to false for good reason) does not - it also appears to getting stuck in the same filter loop (or whatever is happening - the stack trace is so big that Intellij is like "nah man") as the .htacess method. Making progress.
Huzzah, I managed to get it! It was a right pain the butt since I couldn't figure out how to turn on debugging and see what the filter was actually doing, but alas, I have succeeded!
Spent one metric crap ton of time using a regex tester, and this is what I came up with. I am by no means even remotely close to a regex master, so please try to contain your nausea should you have any.
<urlrewrite use-query-string="true">
<rule match-type="regex" enabled="true">
<note>
- "/post/**" and "/user/.../**" are optional - this is because when you're on, say, "/post/20" and you hit
F5, the browser will attempt to get the static assets from "/post/**"
- the second group is used to see if the request is for a static asset
- take advantage of back references and forward only the part that matches the second group
- i.e. "/post/20" as URI -> hit F5 -> "/post/scripts/mainController.js" request of server -> "/scripts/mainController.js" forwarded
- i.e. "/user/Tester/home" -> hit F5 -> "/user/Tester/scripts/mainController.js" -> "/scripts/mainController.js" forwarded
</note>
<condition type="request-uri" operator="equal">\/?(post\/|user\/[a-zA-Z0-9]+\/)(.*.(html|css|jpe?g|gif|png|js|ico|txt|pdf))</condition>
<from>^.*$</from>
<to last="true">/%2</to>
</rule>
<rule match-type="regex" enabled="true">
<note>
Any URI that is prefaced with "/api/open/**" or "/api/secured/**" will be allowed through unmodified.
</note>
<condition type="request-uri" operator="equal">\/api\/(open|secured)\/([a-zA-Z0-9\/]+)</condition>
<from>^.*$</from>
<to last="true">-</to>
</rule>
<rule match-type="regex" enabled="true">
<note>
- Register, browse, search, and upload are all single level urls - the "\z" is to match the end of the string,
otherwise "/register" would match "/registerController.js"
- Inbox CAN be like "/inbox/favorites" so that's why it has a secondary regex - my Regex-Fu isn't good enough to combine
- Settings always has a secondary level
- User always has either home, gallery (w/ page and number), or favorites (w/ page and number)
- A post will always have a number
</note>
<condition type="request-uri" operator="equal" next="or">\/(register\z|browse\z|search\z|upload\z|inbox\z|tag\z)</condition>
<condition type="request-uri" operator="equal" next="or">\/inbox\/(favorites\z|uploads\z|comments\z)?</condition>
<condition type="request-uri" operator="equal" next="or">\/settings\/[A-Za-z-_0-9]+</condition>
<condition type="request-uri" operator="equal" next="or">\/user\/[A-Za-z-_0-9]+\/(home\z|gallery\/[0-9]+\/[0-9]+|favorites\/[0-9]+\/[0-9]+)</condition>
<condition type="request-uri" operator="equal" next="or">\/post\/[0-9]+</condition>
<from>^.*$</from>
<to last="true">/</to>
</rule>
The rules are not as general as I'd like, but they are functional (I have a sneaking suspicion that those five conditionals daisy chained together are a bit of a performance hit). The rules are pretty much specifically tailored solely to my needs but hopefully they can at least be starting point to anybody else who was in my shoes about 4 days ago.
Another important thing to take note of is that in your Angular config (if you're using HTML5 mode - I don't believe that the following is required for hashbang mode), make sure you set requiredBase to true, like:
$locationProvider.html5Mode({
enabled: true,
requireBase: true
});
and include a
<base href="/">
in the <head> of your index.html file. If you don't, Angular will get confused and parts of your application might not quite load correctly - parts of my URI were being trimmed, for example.
Also, tip for anybody new to using .htaccess / UrlRewriteFilter, go get yourself Postman in order to test your rules - probably a major "well, duh" for most, but for the rest of us it'll be a life saver :)
If anybody has any tips on how to improve the efficiency / combine the regex's at all, please let me know.

In Spring Webflow how do I transition from a failed on-start evaluate

I'm new to Spring Webflow and I'm trying to modify an existing flow to check user authorization for using the flow based on several rules. There doesn't seem to be an obvious (widely documented) method of transitioning from an evaluation to some kind of end condition. Transitions I understand are not allowed in on-start. Other than throwing an exception is there a graceful way to transition? Thanks.
Here is a form is created for edit. I added the authorization checking code to the referenced method. I could add a separate evaluate before that to check the authorization but I still have the transition problem.
<on-start>
<evaluate expression="solutionCreateEditFlowHelper.findDocumentForEdit(requestParameters.solutionId)" result="flowScope.documentForm"></evaluate>
>
you don't always need <on-start>. you can have a decision state as starting state, and check inside that decision state if your condition is true or false, if true then transition to your view-state or other state, if not transition to a end state with a view.
let's say you call your flow documentFlow.xml
inside this file, you put a decision-state like the following:
<input name="solutionId" type="long" />
<decision-state id="isDocumentFormSet">
<on-entry>
<evaluate expression="solutionCreateEditFlowHelper.findDocumentForEdit(solutionId)" result="flowScope.documentForm"/>
</on-entry>
<if test="documentForm == null" then="chooseDocument" else="noDocument"/>
</decision-state>
<end-state id="noDocument"/>
<view-state id="chooseDocument">
....
</view-state>

Tuckey urlrewrite check if cookie is set

I am trying to check if given cookie exists with given tag in urlrewrite.xml:
<condition type="cookie" name="LANGUAGE" operator="notequals"></condition>
but it seams not to work.
Any ideas?
What I had to do is first check for the existence of the parameter|cookie and then compare to the value I wanted...
<rule>
<condition type="parameter" name="theme" operator="equal">^.+$</condition>
<condition type="parameter" name="theme" operator="notequal">^default$</condition>
<set name="themeheader">Theme is %{parameter:theme}</set>
</rule>
Replace type above with cookie and change the name of the cookie you want to find and you should be able to use this. I have tested this and I'm now using this on my server so I know it does what I'd expect.
Hope it helps.

Resources