Skip to content

Instantly share code, notes, and snippets.

@vietj
Created October 29, 2018 10:28
Show Gist options
  • Select an option

  • Save vietj/d0c9b0affc180c1c87e08554d1aa48c4 to your computer and use it in GitHub Desktop.

Select an option

Save vietj/d0c9b0affc180c1c87e08554d1aa48c4 to your computer and use it in GitHub Desktop.
public static void validateHeaderValue(CharSequence seq) {
int state = 0;
// Start looping through each of the character
for (int index = 0; index < seq.length(); index++) {
state = validateValueChar(seq, state, seq.charAt(index));
}
if (state != 0) {
throw new IllegalArgumentException("a header value must not end with '\\r' or '\\n':" + seq);
}
}
private static final int HIGHEST_INVALID_VALUE_CHAR_MASK = ~15;
private static int validateValueChar(CharSequence seq, int state, char character) {
/*
* State:
* 0: Previous character was neither CR nor LF
* 1: The previous character was CR
* 2: The previous character was LF
*/
if ((character & HIGHEST_INVALID_VALUE_CHAR_MASK) == 0) {
// Check the absolutely prohibited characters.
switch (character) {
case 0x0: // NULL
throw new IllegalArgumentException("a header value contains a prohibited character '\0': " + seq);
case 0x0b: // Vertical tab
throw new IllegalArgumentException("a header value contains a prohibited character '\\v': " + seq);
case '\f':
throw new IllegalArgumentException("a header value contains a prohibited character '\\f': " + seq);
}
}
// Check the CRLF (HT | SP) pattern
switch (state) {
case 0:
switch (character) {
case '\r':
return 1;
case '\n':
return 2;
}
break;
case 1:
switch (character) {
case '\n':
return 2;
default:
throw new IllegalArgumentException("only '\\n' is allowed after '\\r': " + seq);
}
case 2:
switch (character) {
case '\t':
case ' ':
return 0;
default:
throw new IllegalArgumentException("only ' ' and '\\t' are allowed after '\\n': " + seq);
}
}
return state;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment