Issue #9554 - add javadoc for illegal vchar methods and move to HttpTokens

Signed-off-by: Lachlan Roberts <lachlan@webtide.com>
This commit is contained in:
Lachlan Roberts 2023-04-18 10:46:29 +10:00
parent c3b6b47915
commit 09e6e6b211
5 changed files with 64 additions and 49 deletions

View File

@ -231,5 +231,60 @@ public class HttpTokens
} }
} }
} }
/**
* This is used when decoding to not decode illegal characters based on RFC9110.
* CR, LF, or NUL are replaced with ' ', all other control and multibyte characters
* are replaced with '?'. If this is given a legal character the same value will be returned.
*
* @param c the character to test.
* @return the original character or the replacement character ' ' or '?'.
*/
public static char sanitizeFieldVchar(char c)
{
switch (c)
{
// A recipient of CR, LF, or NUL within a field value MUST either reject the message
// or replace each of those characters with SP before further processing
case '\r':
case '\n':
case 0x00:
return ' ';
default:
if (c >= 256 || c < ' ')
return '?';
}
return c;
}
/**
* This is used when decoding to not decode illegal characters based on RFC9110.
* CR, LF, or NUL are replaced with ' ', all other control and multibyte characters
* are replaced with '?'. If this is given a legal character the same value will be returned.
*
* @param i the character to test.
* @return the original character or the replacement character ' ' or '?'.
*/
public static int sanitizeFieldVchar(int i)
{
if (i > Character.MAX_VALUE)
return '?';
return sanitizeFieldVchar((char)i);
}
/**
* Checks whether this is an invalid VCHAR based on RFC9110.
* If this not a valid ISO-8859-1 character or a control character
* we say that it is illegal.
*
* @param c the character to test.
* @return true if this is invalid VCHAR.
*/
public static boolean isIllegalFieldVchar(char c)
{
return (c >= 256 || c < ' ');
}
} }

View File

@ -346,47 +346,4 @@ public class Huffman
} }
} }
} }
public static boolean isIllegalCharacter(char c)
{
return (c >= 256 || c < ' ');
}
public static char getReplacementCharacter(char c)
{
switch (c)
{
// A recipient of CR, LF, or NUL within a field value MUST either reject the message
// or replace each of those characters with SP before further processing
case '\r':
case '\n':
case 0x00:
return ' ';
default:
if (c >= 256 || c < ' ')
return '?';
}
return c;
}
public static int getReplacementCharacter(int i)
{
switch (i)
{
// A recipient of CR, LF, or NUL within a field value MUST either reject the message
// or replace each of those characters with SP before further processing
case '\r':
case '\n':
case 0x00:
return ' ';
default:
if (i >= 256 || i < ' ')
return '?';
}
return i;
}
} }

View File

@ -15,6 +15,7 @@ package org.eclipse.jetty.http.compression;
import java.nio.ByteBuffer; import java.nio.ByteBuffer;
import org.eclipse.jetty.http.HttpTokens;
import org.eclipse.jetty.util.CharsetStringBuilder; import org.eclipse.jetty.util.CharsetStringBuilder;
import static org.eclipse.jetty.http.compression.Huffman.rowbits; import static org.eclipse.jetty.http.compression.Huffman.rowbits;
@ -72,7 +73,7 @@ public class HuffmanDecoder
// terminal node // terminal node
int i = 0xFF & rowsym[_node]; int i = 0xFF & rowsym[_node];
i = Huffman.getReplacementCharacter(i); i = HttpTokens.sanitizeFieldVchar(i);
_builder.append((byte)i); _builder.append((byte)i);
_bits -= rowbits[_node]; _bits -= rowbits[_node];
_node = 0; _node = 0;
@ -107,7 +108,7 @@ public class HuffmanDecoder
} }
int i = 0xFF & rowsym[_node]; int i = 0xFF & rowsym[_node];
i = Huffman.getReplacementCharacter(i); i = HttpTokens.sanitizeFieldVchar(i);
_builder.append((byte)i); _builder.append((byte)i);
_bits -= rowbits[_node]; _bits -= rowbits[_node];
_node = 0; _node = 0;

View File

@ -15,6 +15,8 @@ package org.eclipse.jetty.http.compression;
import java.nio.ByteBuffer; import java.nio.ByteBuffer;
import org.eclipse.jetty.http.HttpTokens;
import static org.eclipse.jetty.http.compression.Huffman.CODES; import static org.eclipse.jetty.http.compression.Huffman.CODES;
import static org.eclipse.jetty.http.compression.Huffman.LCCODES; import static org.eclipse.jetty.http.compression.Huffman.LCCODES;
@ -67,7 +69,7 @@ public class HuffmanEncoder
for (int i = 0; i < len; i++) for (int i = 0; i < len; i++)
{ {
char c = s.charAt(i); char c = s.charAt(i);
if (Huffman.isIllegalCharacter(c)) if (HttpTokens.isIllegalFieldVchar(c))
return -1; return -1;
needed += table[c][1]; needed += table[c][1];
} }
@ -88,7 +90,7 @@ public class HuffmanEncoder
for (int i = 0; i < len; i++) for (int i = 0; i < len; i++)
{ {
char c = s.charAt(i); char c = s.charAt(i);
if (Huffman.isIllegalCharacter(c)) if (HttpTokens.isIllegalFieldVchar(c))
throw new IllegalArgumentException(); throw new IllegalArgumentException();
int code = table[c][0]; int code = table[c][0];
int bits = table[c][1]; int bits = table[c][1];

View File

@ -25,10 +25,10 @@ import org.eclipse.jetty.http.HttpHeader;
import org.eclipse.jetty.http.HttpMethod; import org.eclipse.jetty.http.HttpMethod;
import org.eclipse.jetty.http.HttpScheme; import org.eclipse.jetty.http.HttpScheme;
import org.eclipse.jetty.http.HttpStatus; import org.eclipse.jetty.http.HttpStatus;
import org.eclipse.jetty.http.HttpTokens;
import org.eclipse.jetty.http.HttpVersion; import org.eclipse.jetty.http.HttpVersion;
import org.eclipse.jetty.http.MetaData; import org.eclipse.jetty.http.MetaData;
import org.eclipse.jetty.http.PreEncodedHttpField; import org.eclipse.jetty.http.PreEncodedHttpField;
import org.eclipse.jetty.http.compression.Huffman;
import org.eclipse.jetty.http.compression.HuffmanEncoder; import org.eclipse.jetty.http.compression.HuffmanEncoder;
import org.eclipse.jetty.http.compression.NBitIntegerEncoder; import org.eclipse.jetty.http.compression.NBitIntegerEncoder;
import org.eclipse.jetty.http2.hpack.HpackContext.Entry; import org.eclipse.jetty.http2.hpack.HpackContext.Entry;
@ -468,7 +468,7 @@ public class HpackEncoder
for (int i = 0; i < value.length(); i++) for (int i = 0; i < value.length(); i++)
{ {
char c = value.charAt(i); char c = value.charAt(i);
c = Huffman.getReplacementCharacter(c); c = HttpTokens.sanitizeFieldVchar(c);
buffer.put((byte)c); buffer.put((byte)c);
} }
} }