Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions conf/server.xml
Original file line number Diff line number Diff line change
Expand Up @@ -160,6 +160,9 @@
resourceName="UserDatabase"/>
</Realm>

<!-- LowerCaseHeaders valve makes http headers case insensitive, but retains original spelling -->
<Valve className="org.apache.catalina.valves.LowerCaseHeadersValve" />

<Host name="localhost" appBase="webapps"
unpackWARs="true" autoDeploy="true">

Expand Down
57 changes: 57 additions & 0 deletions java/org/apache/catalina/valves/LowerCaseHeadersValve.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
package org.apache.catalina.valves;

import org.apache.catalina.connector.Response;
import org.apache.catalina.valves.ValveBase;
import org.apache.tomcat.util.buf.MessageBytes;
import org.apache.tomcat.util.http.MimeHeaders;

import javax.servlet.ServletException;
import java.io.IOException;
import java.util.*;

import org.apache.juli.logging.Log;
import org.apache.juli.logging.LogFactory;

public class LowerCaseHeadersValve extends ValveBase {
private static final Log log = LogFactory.getLog(LowerCaseHeadersValve.class);

@Override
public void invoke(org.apache.catalina.connector.Request request, Response response) throws IOException, ServletException {
log.debug("in");
// Access the Coyote request (Tomcat's internal request object)
org.apache.coyote.Request coyoteRequest = request.getCoyoteRequest();
MimeHeaders mimeHeaders = coyoteRequest.getMimeHeaders();

// Preserve original header names with case
Map<String, List<String>> originalHeaders = new LinkedHashMap<>();

for (int i = 0; i < mimeHeaders.size(); i++) {
MessageBytes nameMessageBytes = mimeHeaders.getName(i);
MessageBytes valueMessageBytes = mimeHeaders.getValue(i);

String name = nameMessageBytes.toString();
String value = valueMessageBytes.toString();

if(log.isDebugEnabled()) {
log.debug("raw: "+name+": "+value);
}

originalHeaders.computeIfAbsent(name, k -> new ArrayList<>()).add(value);

nameMessageBytes.setString(name.toLowerCase());

if(log.isDebugEnabled()) {
name = nameMessageBytes.toString();
value = valueMessageBytes.toString();
log.debug("current: "+name+": "+value);
}
}

// Store headers in request attributes for downstream use
request.setAttribute("originalHeaders", originalHeaders);

// Continue pipeline
getNext().invoke(request, response);
}
}

5 changes: 0 additions & 5 deletions java/org/apache/coyote/http11/Http11InputBuffer.java
Original file line number Diff line number Diff line change
Expand Up @@ -906,11 +906,6 @@ private HeaderParseStatus parseHeader() throws IOException {
// skipLine() will handle the error
return skipLine(false);
}

// chr is next byte of header name. Convert to lowercase.
if (chr >= Constants.A && chr <= Constants.Z) {
byteBuffer.put(pos, (byte) (chr - Constants.LC_OFFSET));
}
}

// Skip the line and ignore the header
Expand Down