class HttpRequestDecoder extends MessageToMessageDecoder<FullHttpRequest> implements HttpHandler {

    @Override
    protected void decode(ChannelHandlerContext ctx, FullHttpRequest msg, List<Object> out) throws Exception {

        LOG.trace(LOG_RECEIVED_REQUEST, msg);

        final String uri = msg.uri();
        final QueryStringDecoder decoder = new QueryStringDecoder(uri);
        if (decoder.path().equals(nonSecureRedirectAddress)) {
            out.add(new StrictTransportResponse());
            return;
        }

        final String sessionId = getSessionId(msg, this.anonymousAccessAllowed);
        LOG.trace("SessionID: " + sessionId);

        if (decoder.path().equals("/login")) {
            if (msg.method().equals(HttpMethod.GET)) {
                out.add(new X509LoginRequest());
            } else if (msg.method().equals(HttpMethod.POST)) {
                ByteBuf body = msg.content();
                byte[] content = null;
                if (null != body) {
                    content = new byte[body.readableBytes()];
                    body.readBytes(content);
                }
                BasicAuthLoginRequest request = BasicAuthLoginRequest.parseBody(content);
                request.validate();
                out.add(request);
            } else {
                QonduitException e = new QonduitException(HttpResponseStatus.METHOD_NOT_ALLOWED.code(),
                        "unhandled method type", "");
                e.addResponseHeader(HttpHeaderNames.ALLOW.toString(),
                        HttpMethod.GET.name() + "," + HttpMethod.POST.name());
                LOG.warn("Unhandled HTTP request type {}", msg.method());
                throw e;
            }
        } else {
            QonduitException e = new QonduitException(HttpResponseStatus.SEE_OTHER.code(), "Unknown request path", "");
            LOG.warn("Unknown request path {}", decoder.path());
            throw e;
        }

    }

    public  HttpRequestDecoder(Configuration config);

}