StrictReader (will be optimise later) -> use a 1 byte buffer to read data, so it can read bytes when needed without skiping any

This commit is contained in:
jeffcheasey88 2025-04-11 14:39:33 +02:00
parent 2c135c2e26
commit 12f2561921
3 changed files with 369 additions and 8 deletions

View file

@ -1,11 +1,12 @@
package dev.peerat.framework;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.Socket;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@ -23,14 +24,14 @@ public class HttpReader{
private Socket socket;
private InputStream in;
private BufferedReader reader;
private StrictReader reader;
private Map<String, String> headers;
public HttpReader(Socket socket) throws Exception{
this.socket = socket;
this.in = socket.getInputStream();
this.reader = new BufferedReader(new InputStreamReader(in));
this.reader = new StrictReader(this.in);
this.headers = new HashMap<>();
}
@ -66,7 +67,7 @@ public class HttpReader{
}
public int read(char[] buffer) throws IOException{
return this.reader.read(buffer);
return this.reader.read(buffer, 0, buffer.length);
}
public String readLine() throws IOException{
@ -133,4 +134,39 @@ Content-Type: text/javascript
return list;
}
public byte[] readMultipartFile() throws Exception{
int length = Integer.parseInt(getHeader("content-length"));
int headerLength = readLine().length()+2;
length-=headerLength;
for(int i = 0; i < 2; i++){
length-=(readLine().length()+2);
}
byte[] ptn = new byte[2];
read(ptn);
length-=2;
if(ptn[0] == 10){
read(new byte[1]);
length-=1;
}
byte[] file = new byte[0];
while(length > 0){
byte[] buffer = new byte[length];
int read = read(buffer);
if(read < 0) throw new IndexOutOfBoundsException("read -1 on HttpReader");
length-=read;
byte[] copy = new byte[file.length+read];
System.arraycopy(file, 0, copy, 0, file.length);
System.arraycopy(buffer, 0, copy, file.length, read);
file = copy;
}
byte[] cleaned = new byte[file.length-(headerLength+4)];
System.arraycopy(file, 0, cleaned, 0, cleaned.length);
return cleaned;
}
}

View file

@ -1,6 +1,11 @@
package dev.peerat.framework;
import static dev.peerat.framework.RequestType.OPTIONS;
import static dev.peerat.framework.RequestType.POST;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.lang.reflect.Constructor;
@ -9,6 +14,7 @@ import java.net.ServerSocket;
import java.net.Socket;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Matcher;
import javax.net.ssl.SSLServerSocket;
import javax.net.ssl.SSLServerSocketFactory;
@ -17,9 +23,7 @@ import dev.peerat.framework.auth.Authenticator;
public class Router<U extends User>{
public static void main(String[] args){
}
public static void main(String[] args) throws Exception{}
private Locker<Context> logger;
private Locker<Throwable> exceptions;

View file

@ -0,0 +1,321 @@
package dev.peerat.framework;
import java.io.IOException;
import java.io.InputStream;
import java.nio.ByteBuffer;
import java.nio.CharBuffer;
import java.nio.charset.Charset;
import java.nio.charset.CharsetDecoder;
import java.nio.charset.CoderResult;
public class StrictReader {
private boolean skipLF = false;
private int nextChar;
private int nChars;
private char[] cb;
private int markedChar = -1;
private int readAheadLimit = 0;
private InputStream in;
private boolean haveLeftoverChar = false;
private char leftoverChar;
private ByteBuffer bb;
private CharsetDecoder decoder;
StrictReader(InputStream in) {
this.in = in;
this.decoder = Charset.defaultCharset().newDecoder();
this.cb = new char[1];
this.nextChar = this.nChars = 0;
this.bb = ByteBuffer.allocate(1);
this.bb.flip();
}
public boolean ready() throws IOException {
synchronized (this.in) {
ensureOpen();
if (this.skipLF) {
if (this.nextChar >= this.nChars && sdReady())
fill();
if (this.nextChar < this.nChars) {
if (this.cb[this.nextChar] == '\n')
this.nextChar++;
this.skipLF = false;
}
}
return (this.nextChar < this.nChars || sdReady());
}
}
public boolean sdReady() throws IOException {
synchronized (this.in) {
ensureOpen();
return (this.haveLeftoverChar || implReady());
}
}
public int read(char[] paramArrayOfchar, int paramInt1, int paramInt2) throws IOException {
if (paramInt1 < 0 || paramInt1 > paramArrayOfchar.length || paramInt2 < 0
|| paramInt1 + paramInt2 > paramArrayOfchar.length || paramInt1 + paramInt2 < 0)
throw new IndexOutOfBoundsException();
synchronized (this.in) {
ensureOpen();
if (paramInt2 == 0)
return 0;
int i = read1(paramArrayOfchar, paramInt1, paramInt2);
if (i <= 0)
return i;
while (i < paramInt2 && sdReady()) {
int j = read1(paramArrayOfchar, paramInt1 + i, paramInt2 - i);
if (j <= 0)
break;
i += j;
}
return i;
}
}
private int read1(char[] paramArrayOfchar, int paramInt1, int paramInt2) throws IOException {
if (this.nextChar >= this.nChars) {
if (paramInt2 >= this.cb.length && this.markedChar <= -1 && !this.skipLF)
return sdRead(paramArrayOfchar, paramInt1, paramInt2);
fill();
}
if (this.nextChar >= this.nChars)
return -1;
if (this.skipLF) {
this.skipLF = false;
if (this.cb[this.nextChar] == '\n') {
this.nextChar++;
if (this.nextChar >= this.nChars)
fill();
if (this.nextChar >= this.nChars)
return -1;
}
}
int i = Math.min(paramInt2, this.nChars - this.nextChar);
System.arraycopy(this.cb, this.nextChar, paramArrayOfchar, paramInt1, i);
this.nextChar += i;
return i;
}
private void ensureOpen() throws IOException {
if (this.in == null)
throw new IOException("Stream closed");
}
public String readLines() throws IOException{
StringBuilder builder = new StringBuilder();
synchronized (this.in){
ensureOpen();
}
return builder.toString();
}
public String readLine() throws IOException {
StringBuilder stringBuilder = null;
synchronized (this.in) {
ensureOpen();
boolean bool = this.skipLF;
while (true) {
if (this.nextChar >= this.nChars)
fill();
if (this.nextChar >= this.nChars) {
if (stringBuilder != null && stringBuilder.length() > 0)
return stringBuilder.toString();
return null;
}
boolean bool1 = false;
char c = Character.MIN_VALUE;
if (bool && this.cb[this.nextChar] == '\n')
this.nextChar++;
this.skipLF = false;
bool = false;
int j;
for (j = this.nextChar; j < this.nChars; j++) {
c = this.cb[j];
if (c == '\n' || c == '\r') {
bool1 = true;
break;
}
}
int i = this.nextChar;
this.nextChar = j;
if (bool1) {
String str;
if (stringBuilder == null) {
str = new String(this.cb, i, j - i);
} else {
stringBuilder.append(this.cb, i, j - i);
str = stringBuilder.toString();
}
this.nextChar++;
if (c == '\r')
this.skipLF = true;
return str;
}
if (stringBuilder == null)
stringBuilder = new StringBuilder();
stringBuilder.append(this.cb, i, j - i);
}
}
}
private void fill() throws IOException {
int i;
if (this.markedChar <= -1) {
i = 0;
} else {
int j = this.nextChar - this.markedChar;
if (j >= this.readAheadLimit) {
this.markedChar = -2;
this.readAheadLimit = 0;
i = 0;
} else {
if (this.readAheadLimit <= this.cb.length) {
System.arraycopy(this.cb, this.markedChar, this.cb, 0, j);
this.markedChar = 0;
i = j;
} else {
char[] arrayOfChar = new char[this.readAheadLimit];
System.arraycopy(this.cb, this.markedChar, arrayOfChar, 0, j);
this.cb = arrayOfChar;
this.markedChar = 0;
i = j;
}
this.nextChar = this.nChars = j;
}
}
while (true) {
int j = sdRead(this.cb, i, this.cb.length - i);
if (j != 0) {
if (j > 0) {
this.nChars = i + j;
this.nextChar = i;
}
return;
}
}
}
// StreamDecoder
private int sdRead(char[] paramArrayOfchar, int paramInt1, int paramInt2) throws IOException {
int i = paramInt1;
int j = paramInt2;
if (i < 0 || i > paramArrayOfchar.length || j < 0 || i + j > paramArrayOfchar.length || i + j < 0)
throw new IndexOutOfBoundsException();
synchronized (this.in) {
ensureOpen();
if (j == 0)
return 0;
byte b = 0;
if (this.haveLeftoverChar) {
paramArrayOfchar[i] = this.leftoverChar;
i++;
j--;
this.haveLeftoverChar = false;
b = 1;
if (j == 0 || !implReady())
return b;
}
if (j == 1) {
int k = read0();
if (k == -1)
return b == 0 ? -1 : b;
paramArrayOfchar[i] = (char) k;
return b + 1;
}
return b + implRead(paramArrayOfchar, i, i + j);
}
}
boolean implReady() {
return (this.bb.hasRemaining() || inReady());
}
private boolean inReady() {
try {
return (this.in != null && this.in.available() > 0);
} catch (IOException iOException) {
return false;
}
}
int implRead(char[] paramArrayOfchar, int paramInt1, int paramInt2) throws IOException {
CharBuffer charBuffer = CharBuffer.wrap(paramArrayOfchar, paramInt1, paramInt2 - paramInt1);
if (charBuffer.position() != 0)
charBuffer = charBuffer.slice();
boolean bool = false;
while (true) {
CoderResult coderResult = this.decoder.decode(this.bb, charBuffer, bool);
if (coderResult.isUnderflow()) {
if (bool || !charBuffer.hasRemaining() || (charBuffer.position() > 0 && !inReady()))
break;
int i = readBytes();
if (i < 0) {
bool = true;
if (charBuffer.position() == 0 && !this.bb.hasRemaining())
break;
this.decoder.reset();
}
continue;
}
if (coderResult.isOverflow()) {
break;
}
coderResult.throwException();
}
if (bool)
this.decoder.reset();
if (charBuffer.position() == 0) {
if (bool)
return -1;
}
return charBuffer.position();
}
private int read0() throws IOException {
synchronized (this.in) {
if (this.haveLeftoverChar) {
this.haveLeftoverChar = false;
return this.leftoverChar;
}
char[] arrayOfChar = new char[2];
int i = sdRead(arrayOfChar, 0, 2);
switch (i) {
case -1:
return -1;
case 2:
this.leftoverChar = arrayOfChar[1];
this.haveLeftoverChar = true;
case 1:
return arrayOfChar[0];
}
return -1;
}
}
private int readBytes() throws IOException {
this.bb.compact();
try {
int j = this.bb.limit();
int k = this.bb.position();
int b = (k <= j) ? (j - k) : 0;
int m = this.in.read(this.bb.array(), this.bb.arrayOffset() + k, b);
if (m < 0)
return m;
if (m == 0)
throw new IOException("Underlying input stream returned zero bytes");
this.bb.position(k + m);
} finally {
this.bb.flip();
}
int i = this.bb.remaining();
return i;
}
}