Почему мой клапан tomcat не вызывается?

Я пытаюсь реализовать клапан Tomcat (в настоящее время используется 7.0.55), который должен перехватывать каждый запрос, поступающий в службу Tomcat, независимо от соединителя и прочего, независимо от того, есть ли хост с совпадающим именем или контекстом сервлета или что-то еще.

invoke-метод клапана выглядит так:

public class MyValve extends ValveBase {
    public void invoke(Request request, Response response) throws IOException,
            ServletException {
        LOG.trace("Valve is being invoked");
        getNext().invoke(request, response);
    }
}

В системе разработки, тестирование локально, все работает как и прежде. Запрос на любой путь URI на моем коте «localhost» записывает эту строку журнала. В sever.xml клапан настраивается вне любого элемента Host:

<Server port="8005" shutdown="SHUTDOWN">
  ...
  <Service name="Catalina">
    ...
    <Engine defaultHost="localhost" name="Catalina">
      ...
      <Realm ... />
      <Valve className="a.b.c.MyValve" />
      ...
      <Host ...>
      </Host>
    </Engine>
  </Service>
</Server>

Теперь скажем, в файле hosts моей системы домен test.domain.com сопоставлен с 127.0.0.1, и есть один развернутый контекст с именем some-webapp.

Как сказано выше, строка журнала получает печать, когда я вызываю http://localhost:8080/some-webapp/, что, как и ожидалось, и также печатается, когда я вызываю http://localhost:8080/non-existing-webapp/, что также ожидаемо.
То же самое касается домена (который не настроен на сервере). .xml) test.domain.com, поэтому http://test.domain.com/some-webapp/ печатает строку журнала так же, как http://test.domain.com/non-existing-webapp.

Но это не так для сервера, на котором мы тестируем. Здесь Valve вызывается только в том случае, если контекстное имя URI «известно» tomcat, то есть вызов .../some-webapp/ напечатает строку журнала, а вызов .../non-existing-webapp / просто ничего не сделает — клапан вообще не запускается.
Тем не менее, tomcat обрабатывает этот запрос, поскольку ошибка 404, отправляемая клиенту, в этом случае содержит «Apache-Coyote something» в качестве заголовка ответа.

У меня нет идей о том, как отлаживать это дальше, особенно процесс «выбора» tomcat конвейера или чего-то еще - есть какие-нибудь мысли?

Спасибо!


person chammp    schedule 17.11.2014    source источник


Ответы (2)


Оказывается, это вызвано отсутствием ROOT-каталога в каталоге веб-приложений Tomcat. Я думаю, что Tomcat довольно строго фильтрует входящие запросы в очень ранний момент времени, даже до того, как какие-либо клапаны смогут обработать запрос и возиться с ним.
И если нет контекста по умолчанию (т. to) знать(и), что запрос к non-existing-webapp не может быть успешным, и поэтому даже не вызывает клапан(ы). С контекстом по умолчанию Tomcat не может знать, что произойдет с запросом, и, таким образом, клапан получает возможность перехватить запрос.

person chammp    schedule 19.11.2014

В версиях 6 (не уверен, что происходит в более ранних версиях) - 8 Tomcat не вызывает Valve, если он определяет, что требуется перенаправление, поэтому удивительно, что Valves работают надежно только тогда, когда контекст определяется на этапе сопоставления.

Вы можете проверить исходный код (и при желании прикрепить отладчик) класса org.apache.catalina.connector.CoyoteAdapter, где происходит действие

    // Parse and set Catalina and configuration specific
    // request parameters
    req.getRequestProcessor().setWorkerThreadName(THREAD_NAME.get());
    boolean postParseSuccess = postParseRequest(req, request, res, response);
    if (postParseSuccess) {
        //check valves if we support async
        request.setAsyncSupported(connector.getService().getContainer().getPipeline().isAsyncSupported());
        // Calling the container
        connector.getService().getContainer().getPipeline().getFirst().invoke(request, response);

Как видите, клапаны вызываются только в том случае, если postParseRequest возвращает значение true, чего не происходит, например, если Tomcat определяет, что он должен возвращать перенаправление во время postParseRequest. Код, определяющий, что требуется перенаправление:

    // Possible redirect
    MessageBytes redirectPathMB = request.getMappingData().redirectPath;
    if (!redirectPathMB.isNull()) {
        String redirectPath = URLEncoder.DEFAULT.encode(redirectPathMB.toString());
        String query = request.getQueryString();
        if (request.isRequestedSessionIdFromURL()) {
            // This is not optimal, but as this is not very common, it
            // shouldn't matter
            redirectPath = redirectPath + ";" +
                    SessionConfig.getSessionUriParamName(
                        request.getContext()) +
                "=" + request.getRequestedSessionId();
        }
        if (query != null) {
            // This is not optimal, but as this is not very common, it
            // shouldn't matter
            redirectPath = redirectPath + "?" + query;
        }
        response.sendRedirect(redirectPath);
        request.getContext().logAccess(request, response, 0, true);
        return false;
    }

В моем случае перенаправление было установлено в org.apache.catalina.mapper.Mapper.internalMapWrapper(...)

Это может стать неприятностью, если вы используете RemoteIpValve, поскольку это заставляет Tomcat отправлять перенаправления с использованием неправильной схемы.

person Boris Treukhov    schedule 10.12.2015