Giter Club home page Giter Club logo

vertx-web's Introduction

Vert.x-Web

Build Status (5.x) Build Status (4.x) Maven Central CII Best Practices

Vert.x-Web is a set of building blocks for building web applications with Vert.x. Think of it as a Swiss Army Knife for building modern, scalable, web apps.

Please see the main documentation on the web-site for a full description:

Template engines

Template engine implementations are in the template engine sub-project.

vertx-web's People

Contributors

alexlehm avatar billyyccc avatar brunoais avatar cescoffier avatar chrispatmore avatar craig-day avatar dependabot[bot] avatar drakkan avatar emadalblueshi avatar jcarranzan avatar krishnarb3 avatar kromit avatar michaelpog avatar mliberato avatar mystdeim avatar pendula95 avatar phiz71 avatar pk-work avatar pmlopes avatar purplefox avatar qxo avatar rogelio-o avatar shvalb avatar slinkydeveloper avatar tnolli avatar tsegismont avatar victorqrs avatar vietj avatar yeikel avatar zenios avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

vertx-web's Issues

Session support

Allow cookies to lookup a session for the user and retrieve a session object.

It should be possible to store sessions in Vert.x 3.0 clustered shared data, redis and possibly other stores.

Should we handle empty strings as prefix for template engines ?

TemplateEngine engine = HandlebarsTemplateEngine.create(null, "tpl");
Handler<RoutingContext> templateHandler = PathTemplateHandler.templateHandler(engine, "templates", "text/html");

locates files into templates/path.tpl

TemplateEngine engine = HandlebarsTemplateEngine.create("", "tpl");
Handler<RoutingContext> templateHandler = PathTemplateHandler.templateHandler(engine, "templates", "text/html");

locates files into /templates/path.tpl

which fails.

From CachingTemplateEngine line 39 : we add a "/"

Maybe don't if prefix length is 0 ?

Ability to store session client-side

Right now, sessions can only be stored on the server.
However, it would be nice to store sessions on the client (usually done using cookies).

Pros:

  • A session is always available, regardless of which server handled the request
  • There is no sesssion to store/replicate/sync on the server

Cons:

  • Users/Hackers can tamper the session data if it's not properly encrypted

What do you guys thing?
If you feel it's a good enhancement, I can take a stab at it

All the best,
Stéphane

SockJS connection closed unexpectedly after about 100kb of data is sent to server

After about 100kb of worth of data is sent to the SockJS server over the Websocket transport, the connection is unexpectedly dropped.

Debugging shows that it happens in WebSocketTransport.java line 96:

//Invalid JSON - we close the connection
close();

This code path is entered because the message is truncated, which again is because in VertxHandler.java:139 a TextWebSocketFrame msg argument is passed which has .isFinalFragment() === false.

Eventbusbridge: Client handler receives undefined from message.fail()

I have a simple reproducer that shows that the replyHandler of the client receives only 'undefined' when the server replies with message.fail():
https://github.com/leolux/vertx_replyfailinbridge

Why does the reply handler not receive the message that vertxbus.js actually received?
"a["{"address":"b24274d1-0d3c-4158-9dd9-cbe290e95956","failureCode":0,"failureType":"RECIPIENT_FAILURE","message":"send msg.fail() to the client"}"]"

Improve path normalisation

Current algorithm just URLDecodes and removes "..".

We can create an optimised implementation which URL decodes and removes "..", "." and extra "/" in a single iteration.

Routes should be more explicit

It seems that the route handler is not very explicit in terms of routes. E.g if I specify a handler for / , then all my requests, even for /foo/bar are sent to that handler. /admin means /admin/foo/bar is sent to /admin, etc.

This can lead to gotchas where if you didn't create the handlers in the correct order (leaving / at the bottom), then the requests would go to a different handler than what you intended.

I think we should follow the conventions of servlets in this, in that the urls have to be specified exactly as you intend them. And to write a catch-all, you could use wildcards, e.g /* rather than just /. That way its much clearer that you intended it to be a catch all. And if a route isn't specified, then show a generic 404 error page.

I'd also be okay with wildcards like :int , :long, etc.

CookiesTest#testCookiesFields fails on systems with non-English Locale

On my laptop CookiesTest#testCookiesFields fails to parse the expired date because the date formatter produced in Utils.createISODateTimeFormatter() uses the default system locale (French here), instead of a fixed one (Locale.US, Locale.ENGLISH?)

-------------------------------------------------------------------------------
Test set: io.vertx.ext.apex.addons.test.CookiesTest
-------------------------------------------------------------------------------
Tests run: 5, Failures: 0, Errors: 1, Skipped: 0, Time elapsed: 0.098 sec <<< FAILURE! - in io.vertx.ext.apex.addons.test.CookiesTest
testCookieFields(io.vertx.ext.apex.addons.test.CookiesTest)  Time elapsed: 0.032 sec  <<< ERROR!
java.text.ParseException: Unparseable date: "Sat, 03 Jan 2015 02:17:02 GMT"
    at java.text.DateFormat.parse(DateFormat.java:366)
    at io.vertx.ext.apex.addons.test.CookiesTest.testCookieFields(CookiesTest.java:165)

mvn -v yields :

Apache Maven 3.2.3 (33f8c3e1027c3ddde99d3cdebad2656a31e8fdf4; 2014-08-11T16:58:10-04:00)
Maven home: /usr/local/Cellar/maven/3.2.3/libexec
Java version: 1.8.0_25, vendor: Oracle Corporation
Java home: /Library/Java/JavaVirtualMachines/jdk1.8.0_25.jdk/Contents/Home/jre
Default locale: fr_FR, platform encoding: UTF-8
OS name: "mac os x", version: "10.10.1", arch: "x86_64", family: "mac"

Content negotiation for directory listing in StaticServer addon

We should take accept quality settings into account when choosing a content type to use for directory listing.

https://github.com/pmlopes/yoke/blob/develop/framework/src/main/java/com/jetdrone/vertx/yoke/middleware/YokeRequest.java#L46
https://github.com/pmlopes/yoke/blob/develop/framework/src/main/java/com/jetdrone/vertx/yoke/middleware/YokeRequest.java#L463

You could have a weird accepts like:

text/html q=0.9; application/json

in this case you should reply json if you can since it has higher quality (100%)

Auth addon (Oauth etc)

An Auth addon that can handle OAuth/CAS/SAML etc, most probably will delegate to pac4j for the actual logic of redirection etc.

TemplateEngine implementations should support a flag not to block the event loop

The implementation of

TemplateEngine.render(RoutingContext context, String templateFileName, Handler<AsyncResult<Buffer>> handler)

is a blocking operation in some (all?) engine implementations (Even though the signature implies that the result is returned asynchronously)

In some cases, it's OK that render() blocks, because it blocks only for a few milliseconds. But in others cases, calling render() may block for a longer period of time (10-20ms), or even more, depending on the engine implementation and the complexity of the template.
This means that the event loop could be blocked, stuck waiting for the template to finish its job

Ideally, a developper should be able to specify if a template engine should render in a non blocking way.

Weǘe got various options but we could for instance add a flag to the create method of the class MVELTemplateEngine:
static MVELTemplateEngine create(boolean async) { return new MVELTemplateEngineImpl(); }

Or we could create another method that explicitly tells that itś non blocking:
static MVELTemplateEngine createAsync() { return new MVELTemplateEngineImpl(); }

ErrorHandler fails to render exception if Exception.getMessage() returns null.

In snapshot vertx-apex-3.0.0-20150302.172251-43, an ErrorHandler with displayExceptionDetails=true will itself throw an exception when the orginal exception have a null getMessage().

SEVERE: Unexpected exception in route
java.lang.NullPointerException: reasonPhrase
    at io.netty.handler.codec.http.HttpResponseStatus.<init>(HttpResponseStatus.java:478)
    at io.netty.handler.codec.http.HttpResponseStatus.<init>(HttpResponseStatus.java:468)
    at io.vertx.core.http.impl.HttpServerResponseImpl.setStatusMessage(HttpServerResponseImpl.java:122)
    at io.vertx.ext.apex.handler.impl.ErrorHandlerImpl.handle(ErrorHandlerImpl.java:77)
    at io.vertx.ext.apex.handler.impl.ErrorHandlerImpl.handle(ErrorHandlerImpl.java:35)
    at io.vertx.ext.apex.impl.RouteImpl.handleFailure(RouteImpl.java:203)
    at io.vertx.ext.apex.impl.RoutingContextImplBase.iterateNext(RoutingContextImplBase.java:65)
    at io.vertx.ext.apex.impl.RoutingContextImpl.next(RoutingContextImpl.java:98)
    at io.vertx.ext.apex.impl.RoutingContextImpl.doFail(RoutingContextImpl.java:290)
    at io.vertx.ext.apex.impl.RoutingContextImpl.fail(RoutingContextImpl.java:124)
    at io.vertx.ext.apex.impl.RoutingContextImplBase.iterateNext(RoutingContextImplBase.java:73)
    at io.vertx.ext.apex.impl.RoutingContextImpl.next(RoutingContextImpl.java:98)
    at io.vertx.ext.apex.impl.RouterImpl.accept(RouterImpl.java:61)
    at dk.innovasion.support.ApexTest$$Lambda$8/105099923.handle(Unknown Source)
    at io.vertx.core.http.impl.ServerConnection.handleRequest(ServerConnection.java:262)
    at io.vertx.core.http.impl.ServerConnection.processMessage(ServerConnection.java:364)
    at io.vertx.core.http.impl.ServerConnection.handleMessage(ServerConnection.java:129)
    at io.vertx.core.http.impl.HttpServerImpl$ServerHandler.doMessageReceived(HttpServerImpl.java:522)
    at io.vertx.core.http.impl.HttpServerImpl$ServerHandler.doMessageReceived(HttpServerImpl.java:453)
    at io.vertx.core.http.impl.VertxHttpHandler.lambda$channelRead$5(VertxHttpHandler.java:71)
    at io.vertx.core.http.impl.VertxHttpHandler$$Lambda$14/1054055130.run(Unknown Source)
    at io.vertx.core.impl.ContextImpl.lambda$wrapTask$3(ContextImpl.java:258)
    at io.vertx.core.impl.ContextImpl$$Lambda$4/1237598030.run(Unknown Source)
    at io.vertx.core.impl.ContextImpl.executeSync(ContextImpl.java:165)
    at io.vertx.core.http.impl.VertxHttpHandler.channelRead(VertxHttpHandler.java:71)
    at io.vertx.core.net.impl.VertxHandler.channelRead(VertxHandler.java:131)
    at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:308)
    at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:294)
    at io.netty.handler.codec.ByteToMessageDecoder.channelRead(ByteToMessageDecoder.java:182)
    at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:308)
    at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:294)
    at io.netty.channel.DefaultChannelPipeline.fireChannelRead(DefaultChannelPipeline.java:846)
    at io.netty.channel.nio.AbstractNioByteChannel$NioByteUnsafe.read(AbstractNioByteChannel.java:130)
    at io.netty.channel.nio.NioEventLoop.processSelectedKey(NioEventLoop.java:511)
    at io.netty.channel.nio.NioEventLoop.processSelectedKeysOptimized(NioEventLoop.java:468)
    at io.netty.channel.nio.NioEventLoop.processSelectedKeys(NioEventLoop.java:382)
    at io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:354)
    at io.netty.util.concurrent.SingleThreadEventExecutor$2.run(SingleThreadEventExecutor.java:116)
    at java.lang.Thread.run(Thread.java:744)

A reproducer:

package dk.innovasion.support;

import io.vertx.core.AbstractVerticle;
import io.vertx.core.Vertx;
import io.vertx.core.http.HttpServer;
import io.vertx.core.http.HttpServerOptions;
import io.vertx.ext.apex.Router;
import io.vertx.ext.apex.handler.ErrorHandler;

public class ApexTest extends AbstractVerticle {
    @Override
    public void start() throws Exception {
        Router router = Router.router(vertx);

        router.route().path("/ok").handler(ctx -> {
            throw new NullPointerException("message"); 
        });

        router.route().path("/fail").handler(ctx -> {
            throw new NullPointerException(); 
        });
        router.route().failureHandler(ErrorHandler.create(true));

        HttpServerOptions options = new HttpServerOptions();
        options.setPort(8080);

        HttpServer server = vertx.createHttpServer(options);
        server.requestHandler(router::accept).listen();
    }

    public static void main(String[] args) {
        Vertx vertx = Vertx.vertx();

        vertx.deployVerticle(ApexTest.class.getName(), res -> {
            System.out.println(res.succeeded() + " " + res.cause());
        });
    }
}

Hitting localhost:8080/ok shows a nice stacktrace
Hitting localhost:8080/fail shows "Internal Server Error" and the cause exception stacktrace is lost.

Small file uploads are not handled properly by Apex

As reported at https://groups.google.com/forum/#!topic/vertx/X_n6e8PIoEo Apex does not properly handle small files in multipart uploads - while large buffers (> 8000 bytes) seem to be handled properly, smaller ones just lead to a timeout or other failure.

This is demonstrated by the project at https://github.com/millross/apex-small-file-failure which basically rips out a test from BodyHandlerTest within the Apex repository, and modifies it so that two near-identical tests can be run, only differing in the file size uploaded. The one with the small buffer fails, the one with the larger buffer succeeds.

Please review the reproducer and provide feedback if the code is wrong, or look into the problem. If I diagnose the problem I'll attach details to this issue.

Simplify path handling

Currently we allow path matching to match part of a resource, e.g.

"foo*" matches "foobar" as well as "foo/bar"

Propose to simplify this so the path parameter should always be a resource, e.g.

foo/
foo/bar/
foo/bar/wibble.json

this would greatly simplify internal path handling

Issues with CookieHandler

  1. NettyCookie which is being used to provide the cookie functionality, allows a setVersion method to be set on the cookie, to indicate if its http 1.1. Setting that allows the max-age header to be used rather than the deprecated 'expires' header. Therefore a setVersion method should be added to Cookie + CookieImpl

  2. If you're using CookieHandler, it reads all the cookies at the start of the request, and adds them back at the end. However, there's a problem.

In Chrome, the request headers only contain the cookie's name and value, but not the expires / max-age Therefore when its read back by CookieHandlerImpl at the start, the decoded cookie doesn't contain an expires / maxAge.

At the end of the request when the cookie is added back, this time it doesn't have an expiry / max age set. That causes the browser to delete the initial expiry date, and use 'end of session' as the expiry date.

In my case, I was setting a cookie to not expire for 2 years, to keep the user logged in. However the cookie kept being reset to 'expire at end of session' and the user kept being logged out on closing browser window.

A simple workaround is to specify whether the CookieHandler should be read only, or read and write both. Or, it can be split into a CookieReadHandler and CookieWriteHandler

Either that, or it should note when context.addCookie is called, and unless its called, it doesn't add the cookies back and leaves them as they are.

I'd be happy to send a PR for these changes if they're acceptable.

Routing clarifications.

Hey,

Here is a router hierarchy example:

Router apiRouter = Router.router(vertx);
apiRouter.route(HttpMethod.GET, "/product/:pid/items/:item1")
apiRouter.route(HttpMethod.GET, "/product/:pid/items")
apiRouter.route(HttpMethod.GET, "/product/:pid")
apiRouter.route(HttpMethod.GET, "/product")
  1. It could be nice to have sub router for product id to avoid nested paths repetition, this is currently impossible as mounting points can only be used with static paths.
  2. call to api/product/4/f/f/f/f
    will be answered by the last rout because routes matches by startsWith,

With current matching algorithm, how is it possible to disallow a query such /api/product/4/f/2/3/1

Thanks

Route.routeWithRegex not mountPoint aware

A route with a regex will match the whole request path and no only the segment that is mounted. I'm not sure whether this is intended behavior or not.

The matches() method is using the complete request path.
https://github.com/vert-x3/vertx-apex/blob/master/src/main/java/io/vertx/ext/apex/core/impl/RouteImpl.java#L207

It is possible to change the behavior by extracting the subpath from the request path.
This should be done when a mountPoint has been specified.

Example:

      String path  = request.path();
      if (!StringUtils.isEmpty(mountPoint)) {
        path = request.path().replace(mountPoint, "");
      }

How to reproduce:

@Override
public void start() throws Exception {
  Router rootRouter = Router.router(vertx);
  Router apiRouter = Router.router(vertx);
  rootRouter.mountSubRouter("/api, apiRouter);
  apiRouter.routeWithRegex("\\/test").method(GET).handler(rc -> {
      rc.response().end("test");
  });
}

http://localhost:8080/api/test - won't match

Switch for serving files relative to template/static route path configurable

Currently when using template handlers or static handler to load templates/serve files, the files that is looked for is relative to the path for the route on which the handler was set.

This makes sense in some cases, but in others the full path may be desirable. We should make this behaviour configurable by a switch.

Consider supporting etags

Current StaticServer uses last-modified/if-modified-since to detect whether new content needs to be returned.

We should also consider supporting etags. Although I am not 100% sure what this would really buy us.

StaticServer fails while running on windows

static files are allocated using vertx-core's FileResolver which in its turn uses java's Path.resolve().
on windows, WindowsPath.resolve() implementation returns a path with slashes (vs backslashes on linux). while used by URL class, slashes become urlencoded and are turning into %5C. as a result of it in FileResolver line 111 a NoSuchFileException is thrown in attempt to allocate a file with a path like webroot%5Cweb%5Cindex.html

Exception in consumes() when no Content-Type sent

When a route has been configured to consume some specific content types but no Content-Type header is sent, an exception is thrown.

IMHO the route should not match the request unless consumes is set to accept /

Consider unifying auth and session handling

Right now the auth service handles login sessions, and the SessionHandler/SessionStore handles its own sessions.

It would be nice to somehow unifying them so we don't have to deal with two timeouts.

Installation of EventBusBridgeHook missing within SockJSHandlerImpl

At SockJSHandlerImpl line 92 the EventBusBridgeHook does not get installed into the EventBusBridgeImpl, so the hook within SockJSHandlerImpl is useless.
Solution: Either call the method EventBusBrodgeImpl.setHook(this.hook) or create another constructor for the EventBusBridgeImpl and pass it to the constructor when creating the instance.

Add support for Locale in Vert.x Web

In term of work to do, this probably means:

  • Add a class LocaleHandler
  • Add 2 methods: RoutingContext.getLocale() and RoutingContext.setLocale(Locale locale)

For the records, excerpt of a discussion on IRC:

aesteve: just one thing though
aesteve: the most interesting feature is "among the languages available, give me the best matching user locale"
aesteve: say you handle french, german in your context, and the user accept-language is : en_us, fr, it
aesteve: then getLocale should return "fr"

directory listing with static server fails with exception

an attempt to use directory listing through StaticServer.staticServer().setDirectoryListing( true )
throws

ContextImpl Unhandled exception java.lang.NullPointerException
at java.lang.String.replace(String.java:2227)
at io.vertx.ext.apex.addons.impl.StaticServerImpl.lambda$sendDirectory$20(StaticServerImpl.java:433)...

the reason for such behavior is a lack of "title" value in routing context's data map:

directoryTemplate.replace("{title}", context.get("title")).replace("{directory}", normalizedDir)

it's not clear either how to set the title or why is it mandatory at all.

SockJS eventbus bridge negotiation fails for non root paths

Problem:
When a client uses vertxbus.js to bridge the eventbus to the browser and uses a path different from the root path, i.e. vertx.EventBus('http://localhost:8080/notarootpath'), then the first XHR request generated by vertxbus.js goes to "/notarootpath/info". This results in a 404 because the server-side method socketHandler(Handler sockHandler) in the class SockJSHandlerImpl registers this and some other handlers only for the root-path. For example:
router.get("/info").handler(BaseTransport.createInfoHandler(options));

Solution:
The registration of handlers within the method socketHandler() could be rewritten using the corresponding ..withRegex() method. For example: router.get("/info") -> router.getWithRegex(".*/info"). This should work as long as the server relies on the hope that the client only uses vertxbus.js for a bridged eventbus. A cleaner solution could be to pass the routing path into the method SockJSHandlerImpl.bridge:

@OverRide
public SockJSHandler bridge(BridgeOptions bridgeOptions) {
socketHandler(new EventBusBridgeImpl(vertx, bridgeOptions), bridgeOptions.getNonrootpath());
return this;
}

@OverRide
public SockJSHandler socketHandler(Handler sockHandler, String nonrootpath) {
router.get(nonrootpath+"/info").handler(BaseTransport.createInfoHandler(options));
...
}

This could be used as follows:
SockJSHandler sockJSHandler = SockJSHandler.create(vertx);
BridgeOptions bridgeOptions = new BridgeOptions();
bridgeOptions.setNonrootpath("/notarootpath");
sockJSHandler.bridge(bridgeOptions); // <-- Here we pass in the path inside the options
router.route("/notarootpath/*").handler(sockJSHandler);

Notice the asterisk * for the father sockJSHandler is also required.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.