Лучший способ заставить Джерси 2.x отклонять запросы с неверной длиной контента?

1

Мне нужно сделать запросы на отказ от Джерси с неправильной длиной контента. Я проверяю длину содержимого с помощью фильтра ContainerRequestFilter, например:

public class ContentLengthRequiredRequestFilter implements ContainerRequestFilter {
    private static Logger LOG = LoggerFactory.getLogger(ContentLengthRequiredRequestFilter.class);


    @Override
    public void filter(ContainerRequestContext requestContext) throws IOException {

        if (requestContext.getMethod() == javax.ws.rs.HttpMethod.POST
                || requestContext.getMethod() == javax.ws.rs.HttpMethod.PUT) {
            int givenContentLength = requestContext.getLength();

            if (givenContentLength == -1) {
                // no content-length given, but it is is required for PUT and POST requests
        requestContext.abortWith(Response.status(Response.Status.LENGTH_REQUIRED).entity("No content-length provided.").build());

            } else {
                // now check if the given content-length is actually correct.
                // since I only have a reference to an entity stream, it seems to be that
                // reading the entire stream and then resetting it is not a good solution.

                // Should I be checking this somewhere else, perhaps somewhere the entity is already available or where I can get the total size of the body without causing the stream to be read twice? Or is there a better way to get the body size here?

            }

        }

    }
}

Как вы можете видеть в комментарии к блоку кода, следует ли мне проверять это где-то еще, возможно, где-то объект уже доступен или где я могу получить общий размер тела, не заставляя поток читать дважды? Или есть лучший способ получить там размер тела?

Спасибо!!

  • 0
    Я думаю, что это очень сильно зависит от вашей полезной нагрузки. Если ваша полезная нагрузка также содержит имя файла, например, длина вашего содержимого отличается. Я бы проверил это в классе ресурсов, как правило.
Теги:
filter
rest
jersey-2.0
content-length

1 ответ

0
Лучший ответ

Если вы не хотите буферизовать входящую сущность (входной поток), я бы посмотрел интерфейс ReaderInterceptor. Экземпляры этого контракта вызывают только в тех случаях, когда входящие запросы содержат объект (обычно POST, PUT). В перехватчике вы можете в значительной степени делать что-либо с сущностью. Простой фрагмент (не охватывающий все случаи) может выглядеть так:

public class MyInterceptor implements ReaderInterceptor {

    @Override
    public Object aroundReadFrom(final ReaderInterceptorContext context) throws IOException, WebApplicationException {
        final InputStream old = context.getInputStream();
        final String first = context.getHeaders().getFirst("Content-Length");
        final Long declared = first == null ? -1 : Long.valueOf(first);

        context.setInputStream(new InputStream() {

            private long length = 0;
            private int mark = 0;

            @Override
            public int read() throws IOException {
                final int read = old.read();
                readAndCheck(read != -1 ? 1 : 0);
                return read;
            }

            @Override
            public int read(final byte[] b) throws IOException {
                final int read = old.read(b);
                readAndCheck(read != -1 ? read : 0);
                return read;
            }

            @Override
            public int read(final byte[] b, final int off, final int len) throws IOException {
                final int read = old.read(b, off, len);
                readAndCheck(read != -1 ? read : 0);
                return read;
            }

            @Override
            public long skip(final long n) throws IOException {
                final long skip = old.skip(n);
                readAndCheck(skip != -1 ? skip : 0);
                return skip;
            }

            @Override
            public int available() throws IOException {
                return old.available();
            }

            @Override
            public void close() throws IOException {
                old.close();
            }

            @Override
            public synchronized void mark(final int readlimit) {
                mark += readlimit;
                old.mark(readlimit);
            }

            @Override
            public synchronized void reset() throws IOException {
                this.length = 0;
                readAndCheck(mark);
                old.reset();
            }

            @Override
            public boolean markSupported() {
                return old.markSupported();
            }

            private void readAndCheck(final long read) {
                this.length += read;

                if (this.length > declared) {
                    throw new WebApplicationException(
                            Response.status(Response.Status.LENGTH_REQUIRED)
                                    .entity("No content-length provided.")
                                    .build());
                }
            }
        });

        final Object entity = context.proceed();

        context.setInputStream(old);

        return entity;
    }
}

В перехватчике выше я устанавливаю свой собственный поток ввода, который подсчитывает и проверяет количество байтов, считанных из исходного входного потока. Однако эта реализация также зависит от того, как базовый контейнер обрабатывает входной поток (т.е. Он также проверяет длину содержимого при чтении входного потока).

  • 0
    Человек, это идеальный ответ, это именно то , чего я пытался достичь. Спасибо!!

Ещё вопросы

Сообщество Overcoder
Наверх
Меню