본문 바로가기

Programing/OpenSource

[tomcat] HttpServletRequest.getHeader

헤더를 보면 가끔 대소문자를 가리지 않고 동작하는 경우가 있어서 확인을 해보았다.

 

package javax.servlet.http;

public interface HttpServletRequest extends ServletRequest {
    /**
     * Returns the value of the specified request header as a
     * <code>String</code>. If the request did not include a header of the
     * specified name, this method returns <code>null</code>. If there are
     * multiple headers with the same name, this method returns the first head
     * in the request. The header name is case insensitive. You can use this
     * method with any request header.
     *
     * @param name
     *            a <code>String</code> specifying the header name
     * @return a <code>String</code> containing the value of the requested
     *         header, or <code>null</code> if the request does not have a
     *         header of that name
     */
    public String getHeader(String name);

위의 코드의 주석에도 써 있지만 헤더의 이름은 대소문자에 무관하다고 써있다.

The header name is case insensitive.

구현체에 따라 어떻게 가져올지는 다르겠지만 많이 쓰이는 Tomcat으로 분석을 했다.

톰캣의 경우 RequestFacade에서 요청을 처음 받는다.

package org.apache.catalina.connector;

public class RequestFacade implements HttpServletRequest {
    /**
     * The wrapped request.
     */
    protected Request request = null;
    
    @Override
    public String getHeader(String name) {

        if (request == null) {
            throw new IllegalStateException(
                            sm.getString("requestFacade.nullRequest"));
        }

        return request.getHeader(name);
    }

Request 클래스의 getHeader를 호출한다.

package org.apache.catalina.connector;

public class Request implements HttpServletRequest {

    protected org.apache.coyote.Request coyoteRequest;
    
    @Override
    public String getHeader(String name) {
        return coyoteRequest.getHeader(name);
    }

coyoteRequest 의 getHeader를 호출한다.

package org.apache.coyote;

public final class Request {

    private final MimeHeaders headers = new MimeHeaders();
    
    public String getHeader(String name) {
        return headers.getHeader(name);
    }

MimeHeaders의 getHeader를 호출한다.

내부에서 헤더 이름을 가지고 순회를 하는데 equalsIgnoreCase 로 비교하는 것을 알 수 있다.

package org.apache.tomcat.util.http;

public class MimeHeaders {
    public static final int DEFAULT_HEADER_SIZE=8;
    
    private MimeHeaderField[] headers = new MimeHeaderField[DEFAULT_HEADER_SIZE];
    private int count;

    public String getHeader(String name) {
        MessageBytes mh = getValue(name);
        return mh != null ? mh.toString() : null;
    }
    
    public MessageBytes getValue(String name) {
        for (int i = 0; i < count; i++) {
            if (headers[i].getName().equalsIgnoreCase(name)) {
                return headers[i].getValue();
            }
        }
        return null;
    }
    // ..

RFC

RFC-822  에는 헤더의 이름을 field-name 라고 부르는데(3.1.2.  STRUCTURE OF HEADER FIELDS) 필드의 이름을 구별하는데 대 소문자는 구별하지 않는다고 정의하고 있다.

B.2. SEMANTICSHeaders occur before the message body and are terminated by a null line (i.e., two contiguous CRLFs).

A line which continues a header field begins with a SPACE or HTAB character, while a line beginning a field starts with a printable character which is not a colon.

A field-name consists of one or more printable characters (excluding colon, space, and control-characters). A field-name MUST be contained on one line. Upper and lower case are not distinguished when comparing field-names.