Tony Tony - 2 months ago 8
HTTP Question

How to read http request properly?

How to read HTTP request using InputStream? I used to read it like this:

InputStream in = address.openStream();
BufferedReader reader = new BufferedReader(new InputStreamReader(in));
StringBuilder result = new StringBuilder();
String line;
while((line = reader.readLine()) != null) {
result.append(line);
}
System.out.println(result.toString());


But
reader.readLine()
could be blocked, because there is no guarantee that
null
line will be reached. Of course I can read Content-Length header and then read request in a loop:

for (int i = 0; i < contentLength; i++) {
int a = br.read();
body.append((char) a);
}


But if Content-Length is set too big(I guess it could be set manually for purpose),
br.read()
will be blocked.
I try to read bytes directly from InputStream like this:

byte[] bytes = getBytes(is);

public static byte[] getBytes(InputStream is) throws IOException {

int len;
int size = 1024;
byte[] buf;

if (is instanceof ByteArrayInputStream) {
size = is.available();
buf = new byte[size];
len = is.read(buf, 0, size);
} else {
ByteArrayOutputStream bos = new ByteArrayOutputStream();
buf = new byte[size];
while ((len = is.read(buf, 0, size)) != -1)
bos.write(buf, 0, len);
buf = bos.toByteArray();
}
return buf;
}


But it waits forever. What do?

Answer

If you are implementing HTTP server you should detect the end of the request according to HTTP specification. Wiki - https://en.wikipedia.org/wiki/Hypertext_Transfer_Protocol

First of all, you should read a request line, it is always a single line. Then read all request headers. You read them until you have an empty line (i.e. two line endings - <CR><LF>).

After you have a status line and headers you should decide do you need to read body or no because not all requests might have a body - summary table

Then, if you need a body, you should parse your headers (which you already got) and get Content-Length. If it is - just read as many bytes from the stream as it is specified. When Content-Length is missing the length is determined in other ways. Chunked transfer encoding uses a chunk size of 0 to mark the end of the content. Identity encoding without Content-Length reads content until the socket is closed.