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:
parent
2c135c2e26
commit
12f2561921
3 changed files with 369 additions and 8 deletions
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
|
|
321
src/dev/peerat/framework/StrictReader.java
Normal file
321
src/dev/peerat/framework/StrictReader.java
Normal 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;
|
||||
}
|
||||
}
|
Loading…
Add table
Reference in a new issue