Skip to content

Empty response when using ContentCachingResponseWrapper, virtual threads and GraphQl all together #1223

@comshepherd

Description

@comshepherd

Hi there!

Recently faced an issue when using ContentCachingResponseWrapper and virtual thread all together

Symptoms:
While performing any (except graphql schema) graphql request you'll get 200 HTTP, empty response body and 'Content-Length:0' as a header

Prerequisites:

  • using graphql, spring boot (3.4.4 in my case)
  • having ContentCachingResponseWrapper in the Filter
  • virtual thread turned on (threads.virtual.enabled: true) in your properties or yaml file

Code:

Filter

import jakarta.servlet.*;
import jakarta.servlet.annotation.WebFilter;
import jakarta.servlet.http.HttpServletResponse;
import java.io.IOException;
import org.springframework.stereotype.Component;
import org.springframework.web.util.ContentCachingResponseWrapper;

@Component
@WebFilter("/graphql")
public class GraphQlContentLengthFilter implements Filter {

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
            throws IOException, ServletException {

        var responseWrapper = new ContentCachingResponseWrapper((HttpServletResponse) response);
        chain.doFilter(request, responseWrapper);
        responseWrapper.copyBodyToResponse();
    }

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        Filter.super.init(filterConfig);
    }

    @Override
    public void destroy() {
        Filter.super.destroy();
    }
}

application.yaml

threads:
  virtual:
    enabled: true

Reasons:
It seems that spring graphql-lib builds response body in async way and with virtual threads on it happens in 2 different threads in incorrect sequence.
First it will add a header with a filter and then write a response body. Therefore when the filter tries to add the header (copyBodyToResponse method) there is no body yet.

Fix:
For now, I don't know how to fix it, further investigation needed. In my case I've just disabled the virtual threads

Metadata

Metadata

Assignees

No one assigned

    Labels

    status: invalidAn issue that we don't feel is valid

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions