Correctly shutting down a websocket handler
by Robin Anil
When a client disconnects, I see that onClose is not being fired. The only
way this seems to be firing if client sents a close frame.
Is there any way to detect disconnection and immediately close all the
opened resources.
Robin
Robin Anil | Software Engineer
1 year, 3 months
Better logging for predicates
by Brad Wood
I've been using Tuckey Rewrites for a long time and one of my favorite
things about it is the very rich amount of debug and trace logging
information it has. There's not another rewrite engine out there I've seen
that makes it this easy to debug what's happening. The trace level logging
gives you a full blow-by-blow of each rule that's processed, what the input
was, and what the result of each condition was.
As much as I love Undertow's predicates and handlers, the logging is, well,
abysmal :) I'd like to do some work to improve what gets sent to the
request_logger for debugging the predicates and handlers that fire for a
request as part of the PredicatesHandler. My high-level approach is as
follows:
- Override the toString() method in each of the built-in predicates and
handlers to create a basic text representation of them that isn't too far
from the predicate language.
- Add logging at key points in the PredicatesHandler that captures each
predicate as it is evaluated as well as the result of that predicate and
the next handler to be invoked.
- I'd probably say a single debug log entry for every matched predicate
for basic high-level debugging of predicates that had some sort of effect
on the request.
- And then a trace log entry with all the juicy details of each
predicate whether it was matched or not for debugging why predicates aren't
working correctly
So again, I'm offering to work on this and contribute it to Undertow as a
pull, but I'd like some feedback on my idea and a general sanity check on
whether I'm wasting my time here. Well, honestly, I'll probably do the
work regardless because the user's of my Undertow-powered tool will need
it, but I'd like to know if these improvements would be welcomed into the
core.
Thanks!
~Brad
*Developer Advocate*
*Ortus Solutions, Corp *
E-mail: brad(a)coldbox.org
ColdBox Platform: http://www.coldbox.org
Blog: http://www.codersrevolution.com
4 years, 5 months
Building Undertow
by Brad Wood
I'm trying to build Undertow using the (sparse) instructions here and
having a heck of a time.
https://undertow.io/undertow-docs/undertow-docs-2.1.0/index.html
cd undertow && mvn install
So firstly, I'm not super familiar with Maven (not a full time java dev)
but when I skip the tests, the build fails. Here is the note in the docs,
which is confusing for a couple reasons:
If you attempt to build with -Dmaven.test.skip=true for your initial build
> the build will fail, as the core test jar will not be built and the Servlet
> module has a test scoped dependency on this jar. Either use -DskipTests,
> or just let the tests run the first time.
>
- First it says the build will fail if the tests are skipped, but then
seems to imply that I can work around this by setting some system
properties.
- What is the difference between the *maven.test.skip* property and the
*skiptests* property? Do I need both of them?
If I try to run the build like so (Using Maven 3.6.3 and java 11) using a
fresh clone of the Undertow repo with the "master" branch checked out:
mvn install -Dmaven.test.skip=true -DskipTests
I get this build failure still:
[ERROR] Failed to execute goal on project undertow-servlet: Could not
> resolve dependencies for project
> io.undertow:undertow-servlet:jar:2.1.4.Final-SN
> APSHOT: Could not find artifact
> io.undertow:undertow-core:jar:tests:2.1.4.Final-SNAPSHOT -> [Help 1]
>
So, I'm not sure what to do there. The docs state that setting those JVM
args is an alternative to running the tests but it doesn't work.
Now, the first thing I tried was actually just to let the tests run, but
this proved to be even more troublesome than skipping the tests! I get
tons of test failures and other errors and the behavior differs whether I'm
using Java 8 or Java 11 (fun!) and the tests usually just hang and won't
complete.
When I run the build (with tests) on Java 1.8.0_161 they hang on this test
and never finish.
[INFO] Running io.undertow.server.handlers.ReceiverTestCase
When I run the build (with tests) on Java 11.0.6, I get the following
errors:
[ERROR]
> testSpnegoSuccess(io.undertow.server.security.SpnegoDigestAuthenticationTestCase)
> Time elapsed: 0.01 s <<< FAILURE!
> java.lang.AssertionError: Expected header not found.
>
> [ERROR]
> testSpnegoSuccess(io.undertow.server.security.SpnegoBasicAuthenticationTestCase)
> Time elapsed: 0 s <<< FAILURE!
> java.lang.AssertionError: Expected header not found.
>
> [ERROR]
> testSpnegoSuccess(io.undertow.server.security.SpnegoAuthenticationTestCase)
> Time elapsed: 0 s <<< FAILURE!
> java.lang.AssertionError: expected:<401> but was:<403>
>
> [ERROR]
> testNonDefaultFileSystem(io.undertow.server.handlers.file.PathResourceManagerTestCase)
> Time elapsed: 0.042 s <<< FAILURE!
> java.lang.AssertionError: expected:</dir/resource.txt> but
> was:</dir/./resource.txt>
>
> [ERROR]
> testRegexPattern(io.undertow.server.handlers.SameSiteCookieHandlerTestCase)
> Time elapsed: 0.027 s <<< ERROR!
> javax.net.ssl.SSLException: Connection reset
>
And then it hangs on the same test case that Java 8 hangs on
(io.undertow.server.handlers.ReceiverTestCase)
What does it take to get a local build of Undertow working? If it matters,
I'm trying to build on a Windows 7 machine.
Thanks!
~Brad
*Developer Advocate*
*Ortus Solutions, Corp *
E-mail: brad(a)coldbox.org
ColdBox Platform: http://www.coldbox.org
Blog: http://www.codersrevolution.com
4 years, 5 months
transferFrom writes more than requested
by Nate
With the code below, the expected result and what I see on Windows 10 is:
position: 10, count: 20
result: 20
On Debian 10 I see:
position: 10, count: 20
result: 16364
I believe transferFrom should never return more than the count passed to
it, so this seems like a bug? I'm happy to give more information if needed.
Note the Undertow buffer size is 16364. Also, on Debian it really did write
16364 bytes to the output channel.
Cheers,
-Nate
int position = 10;
int count = 20;
StreamSinkChannel output = exchange.getResponseChannel();
FileChannel input = new RandomAccessFile(file, "r").getChannel();
while (count > 0) {
long result;
while (true) {
System.out.println("position: " + position + ", count: " + count);
result = output.transferFrom(input, position, count);
System.out.println("result: " + result); // expected: <= 20
if (result!= 0L) break;
try {
output.awaitWritable();
} catch (InterruptedIOException ignored) {
}
}
count -= result;
position += result;
}
4 years, 5 months
More rewrite handler testing and questions
by Brad Wood
So, in my bid to put the predicate language through the paces, I've been
testing out all the rewrite rules I've ever used with mod_rewrite or Tuckey
Rewrite to see if Undertow's handlers are up to the task.
I've run into an issue again with probably the most common rewrite rule of
any CFML app using an MVC framework, which is a rule that creates so-called
"SES" URLs and force all requests through a front controller design
pattern.
Basically
site.com/home/about
gets rewritten to
site.com/index.cfm/home/about
Here you can see how this rule is typically accomplished in Apache httpd,
Nginx, IIS, and Tuckey:
https://coldbox.ortusbooks.com/the-basics/routing/requirements/rewrite-rules
The hang up is that* any incoming path that maps to an actual file* skips
the rewrite rule. That way* /images/logo.jpg* doesn't get rewritten.
So here was my first stab at it with Undertow's predicate language-- it
seemed simple enough:
not file and not directory -> rewrite('/index.cfm/%{RELATIVE_PATH}')
But our old friend the servlet of course is nowhere to be found since my
"file" and "directory" predicates were executing in the root handler chain
so there is no concept of a servlet's context root with which to resolve
file system paths.
So basically, I understand exactly why this doesn't work, but I feel that
we need to find a way to make this work. This is a feature that pretty
much every rewrite engine I've ever used has-- the ability to test the file
system to see if a file or directory exists. Can we discuss the following
options?
- Find a way for the root handler chain to access the deployment's
resource manager
- Find a way for the rewrite handler to correctly affect not only the
exchange but also (optionally) the HttpServletRequest so it's possible to
rewrite the URL inside of the servlet's handler chain. I know for certain
this is possible because the Tuckey Rewrite engine is implemented as a
servlet filter.
I would prefer the first option since I do like having the predicates in
the root handler chain so it can run as early as possible.
Thanks!
~Brad
*Developer Advocate*
*Ortus Solutions, Corp *
E-mail: brad(a)coldbox.org
ColdBox Platform: http://www.coldbox.org
Blog: http://www.codersrevolution.com
4 years, 5 months
Undertow Request Lifecycle
by Brad Wood
I hate asking generic questions, but I'm looking for a little understanding
or clarification on request lifecycles. If you haven't noticed, I've had
several recent threads that touch on this. Before anyone asks,
- Yes, I have read all the docs I can find on this Ex
http://undertow.io/undertow-docs/undertow-docs-2.0.0/undertow-request-lif...
http://undertow.io/undertow-docs/undertow-docs-2.0.0/#listeners-2
http://undertow.io/undertow-docs/undertow-docs-2.0.0/servlet-using-non-bl...
- Yes, I have Google and read 3rd party docs and guides on Undertow. Ex:
https://www.oreilly.com/library/view/jboss-developers-guide/9781788296199...
- Yes, I have spent hours reviewing the code and experimenting
I've learned a lot, but there's a couple elusive things that all the docs
and guides I see don't quite seem to satisfactorily explain for me.
I'm trying to get some clarification on exactly what part of the request
happens inside the xnio worker thread and which part runs inside the
ThreadPoolExecutor. My server bootstrap wraps a number of various
HttpHandlers around the handler that I set into the server builder and I
had originally assumed that those handlers were part of the same handler
chain that invoked the servlet. This appears to not be the case. The
handler chain I pass to the server builder appears to execute as part of
the org.xnio.nio.WorkerThread.run() thread, while my servlet code executes
inside a thread pool executor.
Both stack traces show that there is a chain of handler.handleRequest()
calls, but this duality causes some confusion and troubles for me. It also
seems to explain to an extent why Stuart's previous messages treated the
"servlet" as a concept so far removed from the initial handler chain.
Even docs like the last link I provided above that contain this image...
[image: image.png]
make it sound like there is a single "root handler". However,
*executeRootHandler* appears in the stack traces of both the XNIO worker as
well as during the servlet chain in the thread pool executor.
at
> io.undertow.server.handlers.SSLHeaderHandler.handleRequest(SSLHeaderHandler.java:105)
> *at io.undertow.server.Connectors.executeRootHandler(Connectors.java:376)*
> at
> io.undertow.server.protocol.http.HttpReadListener.handleEventWithNoRunningRequest(HttpReadListener.java:255)
at
> io.undertow.servlet.handlers.ServletInitialHandler$1.handleRequest(ServletInitialHandler.java:99)
> *at io.undertow.server.Connectors.executeRootHandler(Connectors.java:376)*
> at io.undertow.server.HttpServerExchange$1.run(HttpServerExchange.java:830)
This has proved to create difficulty in trying to accomplish seemingly very
simple tasks with Undertow. For example, an example I gave in a previous
thread was a simple task of logging every HTTP request that returned a
non-successful status code. Seems easy enough, right? However...
- I can't use an exchange complete listener because it doesn't fire with
handlers like *response-code* that end the exchange
- I can't wrap the servlet handler chain because that chain is never
invoked if the exchange is ended first by my predicates
- I can't wrap the handler chain being run in the XNIO listener because
it doesn't wrap the servlet chain so my "before" and "after" code all runs
before the servlet chain starts.
I would love any help and insight both on my general question for
documentation regarding the two separate handler chains as well as my more
specific question above about implementing something as simple as a
handler/listener that always runs at the end of an exchange.
Thanks!
~Brad
*Developer Advocate*
*Ortus Solutions, Corp *
E-mail: brad(a)coldbox.org
ColdBox Platform: http://www.coldbox.org
Blog: http://www.codersrevolution.com
4 years, 5 months
response-code handler bypasses configured error pages
by Brad Wood
When I configure an error page similar to this:
servletBuilder.addErrorPage( new ErrorPage( "404.html", 404));
This works great when I hit a path in my browser that doesn't exist. The
contents of the *404.html* file is served with a response code of *404*.
However, if I also use the predicate language to define something like:
path(/box.json)->response-code(404)
and then I hit *localhost/box.json* in my browser, I get a *404* status
code but with no response body.
- The docs say the response-code handler ends the exchange, but
should it still respect the error pages?
- How can I modify my use of Undertow to respect the error pages
when using the response-code handler?
- I've seen in the docs the ability to have a
*addDefaultResponseListener()* but I'm not sure if it is the correct
solution for this, nor how I would access the error page configuration
dynamically as to not need to duplicate my work.
Thanks!
~Brad
*Developer Advocate*
*Ortus Solutions, Corp *
E-mail: brad(a)coldbox.org
ColdBox Platform: http://www.coldbox.org
Blog: http://www.codersrevolution.com
4 years, 5 months
Max and Min content size predicates are implemented backwards
by Brad Wood
These two predicates from undertow are named/implemented backwards. The
"max" should be ensuring the provided value is at least *as small or
smaller* and the "min" should be ensuring the provided value is at least *as
big or bigger*. But here are the descriptions of each one.
*MinContentSizePredicate*
> Predicate that returns true if the Content-Size of a request is below a
> given value.
*MaxContentSizePredicate*
> Predicate that returns true if the Content-Size of a request is above a
> given value.
So to spell it out, if someone uses the following predicate:
max-content-size(5)
That means they are saying the maximum content size is 5 bytes. So, here's
a quick truth table:
- If content length is *4 bytes *-> should return *true *(under the max)
- if content length is *5 bytes *-> should return *true *(at the max,
but not over)
- if content length is *6 bytes *-> should return *false *(over the max)
But this is the exact opposite of how these predicates have been
implemented. The javadoc matches the behavior, but not the name.
Can I get a quick confirmation this is, in fact, backwards before I enter a
ticket and/or pull request. Note, this will be a breaking change to fix.
Thanks!
~Brad
*Developer Advocate*
*Ortus Solutions, Corp *
E-mail: brad(a)coldbox.org
ColdBox Platform: http://www.coldbox.org
Blog: http://www.codersrevolution.com
4 years, 5 months