1
0
Fork 0
mirror of https://github.com/puma/puma.git synced 2022-11-09 13:48:40 -05:00

ext/puma_http11: handle duplicate headers as per RFC for Java ext

The parser stores headers in a Ruby hash table so that when a header
is found twice its value replaces the old one. As per RFC[1] this is
not correct, since duplicated headers should all be considered. In
particular, they are semantically equivalent to a single header with
comma separated values. In this case, we follow existing practice of
joining values with a comma and a single space character.

[1] See RFC2616 section 4.2:
    http://www.w3.org/Protocols/rfc2616/rfc2616-sec4.html#sec4.2
This commit is contained in:
Alejandro Martinez Ruiz 2015-11-06 17:18:30 +01:00
parent fdfd7b5b0f
commit 800cfeeac3

View file

@ -82,11 +82,11 @@ public class Http11 extends RubyObject {
private Http11Parser.FieldCB http_field = new Http11Parser.FieldCB() { private Http11Parser.FieldCB http_field = new Http11Parser.FieldCB() {
public void call(Object data, int field, int flen, int value, int vlen) { public void call(Object data, int field, int flen, int value, int vlen) {
RubyHash req = (RubyHash)data; RubyHash req = (RubyHash)data;
RubyString v,f; RubyString f;
IRubyObject v;
validateMaxLength(flen, MAX_FIELD_NAME_LENGTH, MAX_FIELD_NAME_LENGTH_ERR); validateMaxLength(flen, MAX_FIELD_NAME_LENGTH, MAX_FIELD_NAME_LENGTH_ERR);
validateMaxLength(vlen, MAX_FIELD_VALUE_LENGTH, MAX_FIELD_VALUE_LENGTH_ERR); validateMaxLength(vlen, MAX_FIELD_VALUE_LENGTH, MAX_FIELD_VALUE_LENGTH_ERR);
v = RubyString.newString(runtime, new ByteList(Http11.this.hp.parser.buffer,value,vlen));
ByteList b = new ByteList(Http11.this.hp.parser.buffer,field,flen); ByteList b = new ByteList(Http11.this.hp.parser.buffer,field,flen);
for(int i = 0,j = b.length();i<j;i++) { for(int i = 0,j = b.length();i<j;i++) {
if((b.get(i) & 0xFF) == '-') { if((b.get(i) & 0xFF) == '-') {
@ -104,7 +104,16 @@ public class Http11 extends RubyObject {
f = RubyString.newString(runtime, "HTTP_"); f = RubyString.newString(runtime, "HTTP_");
f.cat(b); f.cat(b);
} }
req.op_aset(req.getRuntime().getCurrentContext(), f,v);
b = new ByteList(Http11.this.hp.parser.buffer, value, vlen);
v = req.op_aref(req.getRuntime().getCurrentContext(), f);
if (v.isNil()) {
req.op_aset(req.getRuntime().getCurrentContext(), f, RubyString.newString(runtime, b));
} else {
RubyString vs = v.convertToString();
vs.cat(", ");
vs.cat(b);
}
} }
}; };