Skip to content

Commit

Permalink
minor improvements
Browse files Browse the repository at this point in the history
  • Loading branch information
Kartofanych committed Dec 13, 2024
1 parent 2f7bc6c commit 523eb9d
Showing 1 changed file with 102 additions and 46 deletions.
148 changes: 102 additions & 46 deletions src/main/java/org/takes/rq/ChunkedInputStream.java
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,70 @@
*/
final class ChunkedInputStream extends InputStream {

/**
* Empty value for checking the result.
*/
private static final int EMPTY_VALUE = -1;

/**
* Default radix value.
*/
private static final int DEFAULT_RADIX = 16;

/**
* Double slash value.
*/
private static final int DOUBLE_SLASH = '\\';

/**
* Quoted string value.
*/
private static final int QUOTED_STRING = '\"';

/**
* Next line value.
*/
private static final int NEXT_LINE = '\n';

/**
* R value.
*/
private static final int R_VALUE = '\r';

/**
* Semicolon value.
*/
private static final int SEMICOLON = ';';

/**
* Exception for bad state.
*/
private static final String BAD_STATE = "Bad state";

/**
* Exception for bad chunk.
*/
private static final String BAD_CHUNK_SIZE = "Bad chunk size: %s";

/**
* Exception for chunk stream end.
*/
private static final String END_OF_STREAM = "chunked stream ended unexpectedly";

/**
* Exception for crlf expectation state.
*/
private static final String CRLF_EXPECTED = "CRLF expected at end of chunk: ";

/**
* Exception for protocol violation.
*/
private static final String BAD_PROTOCOL = String.format(
"%s%s",
"Protocol violation: Unexpected",
" single newline character in chunk size"
);

/**
* The inputstream that we're wrapping.
*/
Expand Down Expand Up @@ -85,7 +149,7 @@ public int read() throws IOException {
}
final int result;
if (this.eof) {
result = -1;
result = ChunkedInputStream.EMPTY_VALUE;
} else {
++this.pos;
result = this.origin.read();
Expand All @@ -101,7 +165,7 @@ public int read(final byte[] buf, final int off, final int len)
}
final int result;
if (this.eof) {
result = -1;
result = ChunkedInputStream.EMPTY_VALUE;
} else {
final int shift = Math.min(len, this.size - this.pos);
final int count = this.origin.read(buf, off, shift);
Expand Down Expand Up @@ -137,7 +201,7 @@ private void readCrlf() throws IOException {
throw new IOException(
String.format(
"%s %d%s%d",
"CRLF expected at end of chunk: ",
ChunkedInputStream.CRLF_EXPECTED,
crsymbol,
"/",
lfsymbol
Expand Down Expand Up @@ -174,7 +238,7 @@ private static int chunkSize(final InputStream stream)
throws IOException {
final ByteArrayOutputStream baos = ChunkedInputStream.sizeLine(stream);
final String data = baos.toString(Charset.defaultCharset().name());
final int separator = data.indexOf(';');
final int separator = data.indexOf(ChunkedInputStream.SEMICOLON);
final Text number = new Trimmed(
new Unchecked<>(
new Ternary<>(
Expand All @@ -186,44 +250,20 @@ private static int chunkSize(final InputStream stream)
);
try {
return Integer.parseInt(
new UncheckedText(
number
).asString(),
16
new UncheckedText(number).asString(),
ChunkedInputStream.DEFAULT_RADIX
);
} catch (final NumberFormatException ex) {
throw new IOException(
String.format(
"Bad chunk size: %s",
ChunkedInputStream.BAD_CHUNK_SIZE,
baos.toString(Charset.defaultCharset().name())
),
ex
);
}
}

/**
* Possible states of FSM that used to find chunk size.
*/
private enum State {
/**
* Normal.
*/
NORMAL,
/**
* If \r was scanned.
*/
R,
/**
* Inside quoted string.
*/
QUOTED_STRING,
/**
* End.
*/
END;
}

/**
* Extract line with chunk size from stream.
* @param stream Input stream.
Expand Down Expand Up @@ -251,32 +291,26 @@ private static ByteArrayOutputStream sizeLine(final InputStream stream)
private static State next(final InputStream stream, final State state,
final ByteArrayOutputStream line) throws IOException {
final int next = stream.read();
if (next == -1) {
throw new IOException("chunked stream ended unexpectedly");
if (next == ChunkedInputStream.EMPTY_VALUE) {
throw new IOException(ChunkedInputStream.END_OF_STREAM);
}
final State result;
switch (state) {
case NORMAL:
result = nextNormal(state, line, next);
break;
case R:
if (next == '\n') {
if (next == ChunkedInputStream.NEXT_LINE) {
result = State.END;
} else {
throw new IOException(
String.format(
"%s%s",
"Protocol violation: Unexpected",
" single newline character in chunk size"
)
);
throw new IOException(ChunkedInputStream.BAD_PROTOCOL);
}
break;
case QUOTED_STRING:
result = nextQuoted(stream, state, line, next);
break;
default:
throw new IllegalStateException("Bad state");
throw new IllegalStateException(ChunkedInputStream.BAD_STATE);
}
return result;
}
Expand All @@ -292,10 +326,10 @@ private static State nextNormal(final State state,
final ByteArrayOutputStream line, final int next) {
final State result;
switch (next) {
case '\r':
case ChunkedInputStream.R_VALUE:
result = State.R;
break;
case '\"':
case ChunkedInputStream.QUOTED_STRING:
result = State.QUOTED_STRING;
break;
default:
Expand All @@ -321,11 +355,11 @@ private static State nextQuoted(final InputStream stream, final State state,
throws IOException {
final State result;
switch (next) {
case '\\':
case ChunkedInputStream.DOUBLE_SLASH:
result = state;
line.write(stream.read());
break;
case '\"':
case ChunkedInputStream.QUOTED_STRING:
result = State.NORMAL;
break;
default:
Expand All @@ -335,4 +369,26 @@ private static State nextQuoted(final InputStream stream, final State state,
}
return result;
}

/**
* Possible states of FSM that used to find chunk size.
*/
private enum State {
/**
* Normal.
*/
NORMAL,
/**
* If \r was scanned.
*/
R,
/**
* Inside quoted string.
*/
QUOTED_STRING,
/**
* End.
*/
END;
}
}

0 comments on commit 523eb9d

Please sign in to comment.