Hello, any reason why if I read the bodyString of ...
# http4k
r
Hello, any reason why if I read the bodyString of a response of a static ressource like html file in a filter then the response is 500 and content-lenght: 0 ? here's a test:
Copy code
@Test
    fun `response body string for html`() {
        val logAll = Filter { next: HttpHandler ->
            { request ->
                println("REQ: ${request.bodyString()}")
                val response = next(request)
                println("REP: ${response.bodyString()}")
                response
            }
        }

        val server = logAll
                .then(routes("/static" bind static(ResourceLoader.Classpath("static"))))
                .asServer(Undertow(8080)).start()

        val client = DebuggingFilters.PrintResponse()
                .then(OkHttp())

        val response = client(Request(GET, "<http://localhost:8080/static/index.html>"))
        response.status shouldBe 200
    }
static/index.html exists the filter prints it. the result:
Copy code
REQ: 
REP: <!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Hello http4k</title>
</head>
<body>
    <h1>Hello http4k</h1>
</body>
</html>

***** RESPONSE 500 to GET: <http://localhost:8080/static/index.html> *****
HTTP/1.1 500 Internal Server Error
connection: keep-alive
content-length: 0
content-type: text/html
date: Wed, 21 Oct 2020 16:41:37 GMT
Not that's useful to log a html page, but I just added a filter that is logging api calls/responses, and didn't thought to disable it for the swagger static pages and I wasn't able to access the page... took a bit to figure out. I was just wandering if it's by design or a glitch ?
s
@Razvan that's by design, but I appreciate it's a common pitfall. The error you're seeing is because by default static resources are served as streams, and if you consume (i.e to print), they are no longer available for undertow to push it through the wire, that's why it breaks with
stream: closed
exception (invisible unless you debug it)
The solution is trivial though: if you want to use the static content on the server before pushing, you need to "reinject" it into the body:
Copy code
val logAll = Filter { next: HttpHandler ->
        { request ->
            println("REQ: ${request.bodyString()}")
            val response = next(request)
            val bodyPayload = response.bodyString()
            println("REP: $bodyPayload")
            response.body(bodyPayload)
        }
    }
r
Thanks. Yes I thought it might be related to streaming the content (I remember the pain of dealing with logging the stream body in Spring WebFlux). I guess reinjecting works with text files but it brakes the binaries (like images) so better avoiding reading the bodystring of static content. I don’t know if it might help documenting that somewhere...
d
@Razvan one thing you can do if you still want to see the traffic is to use the built in DebuggingFilters. By default they don't consume the body if it's a stream, just print <<stream>>
1
r
Thanks yes I saw that, I'll take a look how it detects if it's a stream maybe I can use the same to not log the streams (I guess it may be helpful even for files upload). unfortunately at work they are control-freaks and want full requests and responses logged in json/logtash, so plain text won't do it.
👍 1