-
Notifications
You must be signed in to change notification settings - Fork 17
Replacing Grizzly with lightweight HTTP server #26
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
Conversation
matthiasblaesing
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I have a bad feeling if people start writing their own http server because its "easy". My experience is, that somewhere something silently breaks and in the end you find, that you broke it yourself.
Given the statement:
Original code was using Grizzly, but I find it too heavyweight and fragile (when I use it in my MPD UI project, it breaks when typing fast).
Leads me to the question: What is fagile in grizzly? It is at the core of the glassfish application server and was/is used for several production sites. I'm pretty sure, that if it would be that fragile I would have seen some fallout from this.
browser/src/main/java/org/netbeans/html/presenters/browser/SimpleServer.java
Outdated
Show resolved
Hide resolved
|
What's fragile in Grizzly? Well, for example the Being able to run I generally agree with not re-inventing the wheels approach, however in this case (which is not a typical HTTP server case) Grizzly brings no benefits and just problems. |
|
You claim that grizzly is fragile - where is your analysis? Where is the issue report against grizzly? So isn't the right summary: "The html4j implementation makes assumption about the underlying http server, that are generally not met by 'normal' http servers, html4j thus has a hard dependency on the bundled http-like implementation". Can you provide me with a debuggable (i.e. interactive) testcase? I'd like to see what happens there. |
Another problem with Grizzly is that it is not maintained anymore. The project page says "...activity is frozen until...", but the problem is that Eclipse already has Jetty and I don't think both projects will survive. It makes no sense to report a bug against Grizzly.
That's not fair, Matthias! The first commit in this PR: 6cf8cc4 actually abstracts away any dependencies on the underlaying server. As such it should be easier than ever to plug in alternative implementation. See
Thanks in advance for any help. I can give you a sample, but I can't guarantee it is going to misbehave. Errors occur only under heavier load. I am fixing the browser presenter to make my mpdui project more reliable. Checkout the mpdui$ mvn clean install -DskipTests # shoudn't matter if it fails after building client subproject
mpdui$ mvn -f client -Pbrowser-presenter process-classes exec:exec -Dexec.server.arg=server -DskipTestsor you can open the project in NetBeans and execute Run Maven - Run as server. Then connect to port 6680 with any browser. Having a running |
|
For grizzly: I assume, that they have to do the same cleanup as the Apache NetBeans project, so I would not discard grizzly that easily. For the mpdui project: I figured out, that I had to initialized the submodules, but building after that fails: |
|
I don't have the access denied problem, locally: I guess a lot of modules were compiled OK. Continue with the second command which works with |
|
Ok - checked out the project, initialized submodules, build on windows, run with build failures (document in previous comment), works in IE 11 and Edge as far as I can say |
|
It would really help to have a minimal reproducer - that way the problem could be pin pointed. The mpdui project is to complex and shows the same problem as many JS projects: It pulls in big piles of depedencies and I'm sidetracked by failures, that are not the ones that need to be fixed. |
| Browser(String app, Config config) { | ||
|
|
||
| Browser(String app, Config config, Supplier<HttpServer<?,?,?, ?>> serverProvider) { | ||
| this.serverProvider = serverProvider != null ? serverProvider : SimpleServer::new; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
By default selects SimpleServer - change to GrizzlyServer to try that one. Plus, as pointed by Matthias, one has to add Grizzly on classpath - currently the grizzly modules only available for compilation & tests - e.g. the provided scope.
Have you switched to Grizzly? You have to change the code in
There is no simple reproducer. Both solutions |
|
The grizzly integration is broken: This happens on Windows and Linux |
|
Ok - Problem is the browser/pom.xml held grizzly as provided dependency |
|
For booting in IE11: I disabled the debugging (set Sorry - I'd have to dig through too much code at this time to help further. Yes this is a repetition: Without an analysis exchanging the http implementation on the server side will only plaster over the underlying problem. Most probably there is a problem in the way the communication between browser frontend and http backend is realised. At this point, instead of throwing with a different implementation at the problem, I would try to reduce the problem to its core. Consider a problem in Swing: You would not throw away the hole implementation, just to find a problem - you'd try to isolate the issue and fix that. I don't think it is helpful to claim grizzly is unstable, my gut feeling is, that it is just much faster/featureful, than the custom implementation that works. So if html4j should not be tied to one http-like implementation, this needs to be pin pointed. Maybe we are seeing a race condition here (JS in the browser is single threaded, but if requests are issued asynchronously, you'll still see race conditions). |
jtulach
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for looking at the code. I am glad I am not the only one who digs through this contribution.
Clearly the problem is a race condition:
- JavaScript to JVM and back may be one set of problems
- Grizzly has four threads processing requests in parallel - that adds another complexity
- the
Fn.PresenterJVM code is then executed in yet another worker thread - the
Genericinfrastructure converting calls to messages isn't bulletproof either
Errors can be in every layer.
To shift your Swing example a bit, let's compare HTML/Java system to Swing. Grizzly is just a small misbehaving component like JTable. Replacing it with another component, even homemade is something people normally do without giving up on whole Swing. E.g. Grizzly isn't essential in this case - presenters and especially Generic one are the important pieces.
| } | ||
| w.write("" | ||
| + " request.open('GET', '" + prefix + "command.js?id=" + id + "', true);\n" | ||
| + " request.setRequestHeader('Content-Type', 'text/plain; charset=utf-8');\n" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As far as I can tell, this is the main idea for running in the browser:
- the browser opens an asynchronous
GETconnection and waits for command from the JVM - the JVM keeps the connection pending
- when it needs to execute a JavaScript, it replies to this connection
- the
waitForCommandis then repeated over and over again
| } | ||
| sb.append("" | ||
| + "request.open('PUT', url, false);\n" | ||
| + "request.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded; charset=utf-8');\n" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Whenever JavaScript needs to invoke something in the JVM, it initiates new blocking PUT request to the JVM server. JVM is supposed to invoke the desired method and returns the result back to JavaScript.
The trouble starts if the JVM needs to execute some JavaScript while processing the PUT request. Then it returns the JavaScript snippet to execute from this method, lets the JavaScript side process it and invoke another PUT request to continue the JVM execution. Most of this logic is handled by the Generic class as far as I can tell.
|
Is there a simple description how I reach a runnable sample? I tried to start the samples from netbeans master, but that results in Unittest failures and is missing documentation how finally run the sample. I'd like to create a minimal browser sample to see the basic machinery, but there are currently to many pitfalls to get to the point. (just noticed, that the failing unittests is no indication, that the project is broken arg) To illustrate: For swing I invoke a single class, get a Frame, a hello wold, an input field. That is dead simple and for HTML4J I get a multi module project - why so complex? |
|
Now I ran the demo and contrary to my observation on mpdui I don't see any network traffic - it looks as if everything is run in the browser? |
|
There is a blog post describing how to turn the browser-presenter on.
It is certainly simple to use Swing to develop desktop application. Is it also that simple to run swing on iOS, Android and in a webpage? |
|
I anyone else follows the blog post and fails (I got an UnsatisfiedLinkError because my Ubuntu System has no webkitget-3.0), you have to:
|
f2ec112 to
255427e
Compare
|
I am satisfied with the current state of |
|
From me this is a -1 (as already indicated). I still don't see an analysis, that suggests, that verifies, that grizzly is the problem here. So from my perspective the underlying problem is covered, but not solved. In the long run we will end up with an unmaintained piece of code. |
|
Thanks for trying to review my clean up, Matthias. If you have comments about my code changes introducing broken code, please add them next to appropriate lines. I see it is not easy dig through all the layers that stay in a way. Feel free to report separate bugs as:
I have to say that I would rather maintain code that I have written than code that has been donated and provably doesn't work. |
You claim grizzly is broken, yet don't substantiate it ("With my code it works" is neither an analysis of the underlying problem, nor a proof). For the record I did not do a review - a review can't be done until the problem is understood and I don't think that is the case here. I expressed, that I don't think the code is a step into the right direction. |
|
You are right in both points, Matthias. First of all I haven't provided enough justification to convince you that the move away from Grizzly is good idea. Second, you haven't provided the review I was hoping for. However rather than continuing discussing soundness of my coding practices, I'd like to ask other reviewers to join. Hopefully we'll be able to focus on the code change and not how good/bad programmer I am. @eppleton, @dukescript, @jlahoda, @sdedic, @tzezula, can you please join and help me find threading bugs in |
|
I believe ceb72dd is the fix Matthias was calling for. Release 1.7.2 seems to provide stable |
c0583d1 to
d8387e0
Compare
|
Now there is an experimental branch jtulach/WebViews and it currently contains a copy of |
I don't want the IDE to open listening network ports to be show a simple GUI. If we really open listening ports with the IDE to show internal UIs, we need to have a more serious discussion, because at that point the IDE becomes a security problem and raises questions like: How is access secured and what is done to ensure that the IDE can't be misused for attacks. |
|
The focus of your review shifted and I take it as a sign that replacing Grizzly is no longer a non-sense.
Alas, that's a valid concern. I'll keep that in mind before creating a PR for jtulach/WebViews. However it is not really related to the question whether such security problem would be caused by Grizzly or home made server. |
|
I am facing a dilemma, Matthias. I need to integrate the jtulach/WebViews in two weeks. Launching the HTTP server is the only solution I have for providing rich refactoring UIs, but the security issue is real. The only way I can think of to avoid it is: Create a random UID. Use it for the first connection between the browser and the server. Then stop accepting further request. That'd be safe, right? Plus stop listening on first wrong UID connection or if no connection is made in 5s... |
Ähm - NetBeans is not such a bad IDE and it is build around Swing. I know it en en vouge to bash Swing and to call it dead and all, but it is here and I don't see it dying (at least there is no valid successor visible right now). Refactoring works right now. And yes, I see it when a HTML renderer is used, it is visually different and looks worse, than plain Swing.
That is one way - or why not use an in-memory transport? That way you don't get zero exposure and direct interaction between the runtimes. For the OpenJFX webview a direct interaction between Java and Javascript code is possible by injecting a Java object into the JS context of the Webview. I bet other environment offer similar options, I doubt, that all webview integration go though a network port for interaction. |
matthiasblaesing
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As already written I would try not to get through the network layer to access a library (I consider a webview a library). If you can't interact with the webview directly it looks broken to me.
In general I still think, that implementing a HTTP server from scratch is not something that should be done. Maybe this is an alternative:
Its a minimal http server embedded in the JDK. Reading the @SInCE info it is there since SOAP support was implemented (at least I think I remember such a comment) and given JEP 408 and that the class was extended in 18 it is unlikely to go away anytime soon.
browser/src/main/java/org/netbeans/html/presenters/browser/SimpleServer.java
Show resolved
Hide resolved
browser/src/main/java/org/netbeans/html/presenters/browser/SimpleServer.java
Outdated
Show resolved
Hide resolved
browser/src/main/java/org/netbeans/html/presenters/browser/SimpleServer.java
Show resolved
Hide resolved
browser/src/main/java/org/netbeans/html/presenters/browser/SimpleServer.java
Outdated
Show resolved
Hide resolved
browser/src/main/java/org/netbeans/html/presenters/browser/SimpleServer.java
Show resolved
Hide resolved
|
The Browser presenter needs an HTTP server to talk to. Original code was using Grizzly, but it has been found too heavyweight adding up to 16MB of overhead in certain setups.
Given the special requirements on the browser/server communication when using
netbeans-html4jproject (single-threaded JavaScript/HTTP handler works the best) - e.g. something else than regular HTTP servers are optimized for, it makes sense to use a dedicated crafted implementation. TheBrowserpresenter continues to support both servers - however, unless one provides Grizzly libraries explicitly, the simple HTTP server is used. To turn grizzly on, add following dependency into your applicationpom.xml:This PR provides simple HTTP implementation that is good enough for all
Browserpresenter purposes.