Serving static content like favicon and woff fonts

1,486 views
Skip to first unread message

Jan Vladimir Mostert

unread,
Oct 23, 2016, 4:50:42 AM10/23/16
to vert.x
Favicon and WOFF Font files, how should they be served?

This works fine for most static files, except for the favicon and .woff font files
router.route().handler(StaticHandler.create())

I've tried this for the favicon and font files:
router.route("/favicon.ico").handler {
 it
.response().putHeader("Content-Type", "image/x-icon").sendFile("webroot/favicon.ico")
}

router
.route("/fonts/glyphicons-halflings-regular.woff").handler {
 it
.response().putHeader("Content-Type", "application/font-woff").sendFile("webroot/fonts/glyphicons-halflings-regular.woff")
}

... but when I directly access the font url, it tries to download the font and Chrome complains and the favicon simply doesn't serve.
Failed to decode downloaded font: http://lion2.jvaas.io/fonts/glyphicons-halflings-regular.woff2
/#/tcr:1 OTS parsing error: Failed to convert WOFF 2.0 font to SFNT
/#/tcr:1 Failed to decode downloaded font: http://lion2.jvaas.io/fonts/glyphicons-halflings-regular.woff
/#/tcr:1 OTS parsing error: incorrect file size in WOFF header
/#/tcr:1 Failed to decode downloaded font: http://lion2.jvaas.io/fonts/glyphicons-halflings-regular.ttf
/#/tcr:1 OTS parsing error: incorrect entrySelector for table directory


The favicon I've tried the favicon handler:
router.route().handler(FaviconHandler.create())

My favicon sits in `src/main/resources/webroot/favicon.ico` and the whole application is packaged as a fat jar using maven shade.

Using the FaviconHandler I'm getting a null pointer exception:


java.lang.RuntimeException: java.lang.NullPointerException

 

 at io
.vertx.ext.web.handler.impl.FaviconHandlerImpl.init(FaviconHandlerImpl.java:148)

 at io
.vertx.ext.web.handler.impl.FaviconHandlerImpl.handle(FaviconHandlerImpl.java:155)

 at io
.vertx.ext.web.handler.impl.FaviconHandlerImpl.handle(FaviconHandlerImpl.java:33)

 at io
.vertx.ext.web.impl.RouteImpl.handleContext(RouteImpl.java:215)

 at io
.vertx.ext.web.impl.RoutingContextImplBase.iterateNext(RoutingContextImplBase.java:78)

 at io
.vertx.ext.web.impl.RoutingContextImpl.next(RoutingContextImpl.java:94)

 at io
.vertx.ext.web.handler.impl.CorsHandlerImpl.handle(CorsHandlerImpl.java:121)

 at io
.vertx.ext.web.handler.impl.CorsHandlerImpl.handle(CorsHandlerImpl.java:38)

 at io
.vertx.ext.web.impl.RouteImpl.handleContext(RouteImpl.java:215)

 at io
.vertx.ext.web.impl.RoutingContextImplBase.iterateNext(RoutingContextImplBase.java:78)

 at io
.vertx.ext.web.impl.RoutingContextImpl.next(RoutingContextImpl.java:94)

 at io
.vertx.ext.web.impl.RouterImpl.accept(RouterImpl.java:79)

 at
Lion$main$9.handle(Lion.kt:104)

 at
Lion$main$9.handle(Lion.kt:43)

 at io
.vertx.core.http.impl.ServerConnection.handleRequest(ServerConnection.java:286)

 at io
.vertx.core.http.impl.ServerConnection.processMessage(ServerConnection.java:412)

 at io
.vertx.core.http.impl.ServerConnection.handleMessage(ServerConnection.java:139)

 at io
.vertx.core.http.impl.HttpServerImpl$ServerHandler.lambda$createConnAndHandle$1(HttpServerImpl.java:712)

 at io
.vertx.core.impl.ContextImpl.lambda$wrapTask$2(ContextImpl.java:314)

 at io
.vertx.core.impl.ContextImpl.executeFromIO(ContextImpl.java:190)

 at io
.vertx.core.http.impl.HttpServerImpl$ServerHandler.createConnAndHandle(HttpServerImpl.java:706)

 at io
.vertx.core.http.impl.HttpServerImpl$ServerHandler.doMessageReceived(HttpServerImpl.java:570)

 at io
.vertx.core.http.impl.HttpServerImpl$ServerHandler.doMessageReceived(HttpServerImpl.java:522)

 at io
.vertx.core.http.impl.VertxHttpHandler.channelRead(VertxHttpHandler.java:76)

 at io
.vertx.core.net.impl.VertxHandler.channelRead(VertxHandler.java:122)

 at io
.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:372)

 at io
.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:358)

 at io
.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:350)

 at io
.netty.handler.codec.ByteToMessageDecoder.fireChannelRead(ByteToMessageDecoder.java:293)

 at io
.netty.handler.codec.ByteToMessageDecoder.channelRead(ByteToMessageDecoder.java:267)

 at io
.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:372)

 at io
.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:358)

 at io
.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:350)

 at io
.vertx.core.http.impl.HttpServerImpl$Http1xOrHttp2Handler.http1(HttpServerImpl.java:1019)

 at io
.vertx.core.http.impl.HttpServerImpl$Http1xOrHttp2Handler.channelRead(HttpServerImpl.java:990)

 at io
.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:372)

 at io
.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:358)

 at io
.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:350)

 at io
.netty.channel.DefaultChannelPipeline$HeadContext.channelRead(DefaultChannelPipeline.java:1334)

 at io
.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:372)

 at io
.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:358)

 at io
.netty.channel.DefaultChannelPipeline.fireChannelRead(DefaultChannelPipeline.java:926)

 at io
.netty.channel.nio.AbstractNioByteChannel$NioByteUnsafe.read(AbstractNioByteChannel.java:129)

 at io
.netty.channel.nio.NioEventLoop.processSelectedKey(NioEventLoop.java:610)

 at io
.netty.channel.nio.NioEventLoop.processSelectedKeysOptimized(NioEventLoop.java:551)

 at io
.netty.channel.nio.NioEventLoop.processSelectedKeys(NioEventLoop.java:465)

 at io
.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:437)

 at io
.netty.util.concurrent.SingleThreadEventExecutor$5.run(SingleThreadEventExecutor.java:873)

 at java
.lang.Thread.run(Thread.java:745)

Caused by: java.lang.NullPointerException

 at io
.vertx.ext.web.handler.impl.FaviconHandlerImpl$Icon.<init>(FaviconHandlerImpl.java:61)

 at io
.vertx.ext.web.handler.impl.FaviconHandlerImpl$Icon.<init>(FaviconHandlerImpl.java:40)

 at io
.vertx.ext.web.handler.impl.FaviconHandlerImpl.init(FaviconHandlerImpl.java:143)

 
... 48 more

Another post on this Google Group mentions the NPE when using the FaviconHandler and says it's resolved by moving the
`favicon.ico` to the correct directory, what is the correct directory for the favicon?

So to sum up, how do I get my favicon to work and how to get .woff files to serve correctly?

I'm on VertX 3.3.3 using Kotlin 1.0.4 if that's of any help.

Tim Fox

unread,
Oct 23, 2016, 7:26:20 AM10/23/16
to vert.x
http://vertx.io/docs/vertx-web/java/#_serving_favicons
http://vertx.io/docs/apidocs/io/vertx/ext/web/handler/FaviconHandler.html

You can specify a path to the file or it will be served from the classpath.

Anything in src/main/resources will go into your jar (that's just a Maven convention), so if you put the file in there it should be found.

Daniel Maier

unread,
Jun 24, 2017, 6:04:03 AM6/24/17
to vert.x
Hi Jan, 

did you find a solution on the woff (woff2) topic?

I have exactly the same problem. If I serve woff (or woff2) files by any other httpd server it is no problem at all, serving it from vert.x something goes wrong.

I have a Angular app which is embedded under webroot in the vert.x fat jar. The StaticHandler from vert.x serves from webroot. Everything looks fine except the font files.

If I deploy the compiled Angular app (/dist) under any other web-server (node-js with http-server, Apache, etc.) it works fine.

Thanks
Daniel

Alexander Lehmann

unread,
Jun 24, 2017, 6:12:44 AM6/24/17
to vert.x
Do you have a small project that shows the issue?

I would think woff files are plain binary files, but maybe there is an issue with the mime-type or something
Message has been deleted
Message has been deleted
Message has been deleted
Message has been deleted
Message has been deleted
Message has been deleted
Message has been deleted
Message has been deleted
Message has been deleted
Message has been deleted
Message has been deleted

Daniel Maier

unread,
Jun 24, 2017, 6:44:46 AM6/24/17
to vert.x

Hi Alexander,


as attachement you can find the dist (build) from the Angular part. If you put that under a simple http-server (like node.js with http-server plugin) it serves the fonts files correctly. You can verify it with the "check" icon next to the "app" text on the main page.


I didn't attach the vert.x project as it is not really important. The question is quite simple: Can you get the static Angular App serve from vert.x web that it also serves the .woff2 (.woff etc.) correctly?


My vert.x main verticle is just doing something that looks like this:


Router router = Router.router(vertx);

router.route().handler(StaticHandler.create());

vertx.createHttpServer()

        .requestHandler(router::accept)

        .listen(8080);


Any help is appreciated :-) Thanks a lot!


Best

Daniel

Message has been deleted

Daniel Maier

unread,
Jun 24, 2017, 6:46:25 AM6/24/17
to vert.x
Sorry I can't attach the .zip with the Angular App...


 at io
.netty.channel<span style="color:#66
Message has been deleted
Message has been deleted
Message has been deleted
Message has been deleted
Message has been deleted

Jan Mostert

unread,
Jun 25, 2017, 8:05:48 AM6/25/17
to vert.x
@Daniel, I think I managed to get it working in one project after messing around with Maven resource plugin, but haven't been able to get it working ever since.
And that favicon and woff fonts might have been cached, so not sure if it actually worked, probably not.
It's very tricky to figure out if it actually works due to chrome caching stuff even when you tell it not to cache anything.

The issue I discovered is that the VertX serves the woff file minus that last byte, so if the woff font is 100 bytes, only 99 bytes will be served and as a result you have a connection that often stays open permanently waiting for that last byte. My guess is, it has something to do with End Of File characters

Here are some things I've tried so far:
https://stackoverflow.com/questions/40197393/serve-favicon-ico-and-other-static-files-with-vertx

The favicon solution worked in one project, but not in another project.
Same with the WOFF / WOFF2 solutions - got it working during one deploy to production, but then it stopped working the next deploy for no reason at all.

Have since moved to Foundation, so haven't had to fight WOFF / WOFF2 issues again.

But yes, it would be nice to just serve those static file from VertX instead of having to run VertX behind NGINX in order to override WOFF / WOFF2 urls and serving those file from NGINX instead.



--
You received this message because you are subscribed to a topic in the Google Groups "vert.x" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/vertx/KIeOpGNwC7E/unsubscribe.
To unsubscribe from this group and all its topics, send an email to vertx+un...@googlegroups.com.
Visit this group at https://groups.google.com/group/vertx.
To view this discussion on the web, visit https://groups.google.com/d/msgid/vertx/c544d418-fa76-458b-9446-20afd014aec0%40googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Jan Mostert

unread,
Jun 25, 2017, 8:24:54 AM6/25/17
to vert.x
Just on a side-note, fonts that were not rendering via VertX was rendering fine when served via Dart
So font-corruption via git or maven was one issue I had, but in the next project it was certainly not an issue since those file were serving fine via Dart.

Not sure how VertX handles different end-of-file / line characters.



Daniel Maier

unread,
Jun 25, 2017, 9:22:30 AM6/25/17
to vert.x
@Jan, exactly... I also realized that I made a big mistake by just copying a sample for the maven-resources-plugin. In that sample the "filtering" tag was inside and set to true.
By doing that the binaries were corrupted afterwards. I didn't noticed that... I realized that it is not related to vert.x neither to the build Angular package!

I forgot to tell that I build a fat jar using the maven-shade-plugin and the maven-resources-plugin. So, vert.x is serving the binaries correctly, I also tried a simple example without Angular.

Thanks a lot for you feedback, I really appreciate it.

Best
Daniel

Tim Fox

unread,
Jun 25, 2017, 10:43:18 AM6/25/17
to vert.x
Should be src/main/resources/favicon.ico


(src/main/resources is a standard Maven directory the contents of which end up in the top level of your jar)

 


 at io
.<span style="c
Reply all
Reply to author
Forward
0 new messages