# Module with embedded jetty server for websockets break Ignition GAN connections

**URL:** <https://forum.inductiveautomation.com/t/module-with-embedded-jetty-server-for-websockets-break-ignition-gan-connections/87343>\
**Category:** Module Development\
**Tags:** ignition81\
**Created:** [March 14, 2024, 3:16pm UTC](https://forum.inductiveautomation.com/t/module-with-embedded-jetty-server-for-websockets-break-ignition-gan-connections/87343 "2024-03-14T15:16:20Z")\
**Posts on this page:** 6\
**Page:** 2

<div class="post-metadata">

**Author:** ![pturmel](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/pturmel/32/3295_2.png) [@pturmel](https://forum.inductiveautomation.com/u/pturmel)\
**Post date:** [June 6, 2024, 8:26pm UTC](https://forum.inductiveautomation.com/t/module-with-embedded-jetty-server-for-websockets-break-ignition-gan-connections/87343/21 "2024-06-06T20:26:05Z")

</div>

Don't use the router. Just add a servlet. Handle each request. Simple.

🤷‍♂️

---

<div class="post-metadata">

**Author:** ![mazeyrat](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/mazeyrat/32/10955_2.png) [@mazeyrat](https://forum.inductiveautomation.com/u/mazeyrat)\
**Post date:** [June 6, 2024, 8:31pm UTC](https://forum.inductiveautomation.com/t/module-with-embedded-jetty-server-for-websockets-break-ignition-gan-connections/87343/22 "2024-06-06T20:31:29Z")

</div>

Ok I see... 👍

> **[WebResourceManager](https://files.inductiveautomation.com/sdk/javadoc/ignition81/8.1.40/com/inductiveautomation/ignition/gateway/web/WebResourceManager.html#addServlet(java.lang.String,java.lang.Class))**
>
> declaration: package: com.inductiveautomation.ignition.gateway.web, interface: WebResourceManager

or I could perhaps try to change the mime in the route handler:  
response.[setContentType](https://www.tabnine.com/code/java/methods/javax.servlet.http.HttpServletResponse/setContentType)(...);

---

<div class="post-metadata">

**Author:** ![paul-griffith](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/paul-griffith/32/37249_2.png) [@paul-griffith](https://forum.inductiveautomation.com/u/paul-griffith)\
**Post date:** [June 6, 2024, 9:25pm UTC](https://forum.inductiveautomation.com/t/module-with-embedded-jetty-server-for-websockets-break-ignition-gan-connections/87343/23 "2024-06-06T21:25:21Z")

</div>

Just set the content type to null in your route mounting implementation, then override it in the actual handler.

---

<div class="post-metadata">

**Author:** ![mazeyrat](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/mazeyrat/32/10955_2.png) [@mazeyrat](https://forum.inductiveautomation.com/u/mazeyrat)\
**Post date:** [June 7, 2024, 9:40am UTC](https://forum.inductiveautomation.com/t/module-with-embedded-jetty-server-for-websockets-break-ignition-gan-connections/87343/24 "2024-06-07T09:40:04Z")

</div>

for files llike mp3 or pdf, bytes have to be converted in String in the route handler ?

I have tried:

```python
return com.inductiveautomation.ignition.common.Base64.encodeBytes(FileUtilities.readFileAsBytes(filePath));

```

but the response is not readable by the browser ???

**what is the way to encode bytes ? is there any httpServletResponse.setCharacterEncoding(xxx); necessary ?**

---

<div class="post-metadata">

**Author:** ![mazeyrat](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/mazeyrat/32/10955_2.png) [@mazeyrat](https://forum.inductiveautomation.com/u/mazeyrat)\
**Post date:** [June 7, 2024, 11:43am UTC](https://forum.inductiveautomation.com/t/module-with-embedded-jetty-server-for-websockets-break-ignition-gan-connections/87343/25 "2024-06-07T11:43:39Z")

</div>

RTM:  
The solution was in the doc: 🤦‍♂️

> **[RouteHandler](https://files.inductiveautomation.com/sdk/javadoc/ignition81/8.1.40/com/inductiveautomation/ignition/gateway/dataroutes/RouteHandler.html)**
>
> declaration: package: com.inductiveautomation.ignition.gateway.dataroutes, interface: RouteHandler

**Called when a the route this handler is attached to is matched in an incoming HTTP request.  
Returns:  
Return an object if your handler should result in a string body returned. Optionally transform the object if it is not already a string by adding a ResponseRenderer to your mounted route. Return null if you have handled the response yourself by directly manipulating the HttpServletResponse.**

```python
httpServletResponse.setContentType("application/pdf");
byte[] bytes = FileUtilities.readFileAsBytes(filePath);
httpServletResponse.setContentLength(bytes.length);
httpServletResponse.getOutputStream().write(bytes);
return null;

```

---

<div class="post-metadata">

**Author:** ![paul-griffith](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/paul-griffith/32/37249_2.png) [@paul-griffith](https://forum.inductiveautomation.com/u/paul-griffith)\
**Post date:** [June 7, 2024, 3:40pm UTC](https://forum.inductiveautomation.com/t/module-with-embedded-jetty-server-for-websockets-break-ignition-gan-connections/87343/26 "2024-06-07T15:40:54Z")

</div>

> [@mazeyrat](#):
>
> ```python
> byte[] bytes = FileUtilities.readFileAsBytes(filePath);
> httpServletResponse.setContentLength(bytes.length);
> httpServletResponse.getOutputStream().write(bytes);
> 
> ```

As an aside, this is a big no-no memory usage wise. You're allocating a byte array (on the heap) for the entire file you're serving, only to immediately discard it when you're writing.

_Much_ better to use a file method that returns an input stream and transfer it, preferably using some buffering mechanism. Apache commons IOUtils should be exposed for your usage in a third party module:

```python
        try (InputStream inputStream = Files.newInputStream(Path.of("somePath")); 
             ServletOutputStream servletOutputStream = res.getOutputStream()) {
            // buffered:
            org.apache.commons.io.IOUtils.copy(inputStream, servletOutputStream);
            // jdk native:
            // inputStream.transferTo(servletOutputStream);
        }

```

[Previous page](https://forum.inductiveautomation.com/t/module-with-embedded-jetty-server-for-websockets-break-ignition-gan-connections/87343.md?page=1)
