0

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?

Denys Kurochkin
  • 1,360
  • 1
  • 18
  • 34
Tony
  • 3,605
  • 14
  • 52
  • 84
  • Why is there no guarantee that `null` line will be reached? According to the documentation, it returns `null if the end of the stream has been reached`. So if connection is closed you will get null after you read the last line. – Denys Kurochkin Sep 07 '16 at 15:38
  • First null line I can reach is separator between headers and request body(like form data). But there is no null line after body. What do? – Tony Sep 07 '16 at 15:43
  • Maybe you get request with an empty body? – Denys Kurochkin Sep 07 '16 at 15:57
  • Headers and body are just delimited by two line separators, so you just have two empty strings, not nulls. Look at the example - https://gist.github.com/dkBrazz/16840b7cfc8248a39dad45e5d15397bd – Denys Kurochkin Sep 07 '16 at 16:09
  • If you just want to forcibly close the hung connection just set the timeout - http://stackoverflow.com/a/6272512/1916536 – Denys Kurochkin Sep 07 '16 at 16:11
  • Your code example is good, but in my case I don't know how many bytes I can read. I don't know when to stop. – Tony Sep 07 '16 at 16:14
  • If you are implementing HTTP server you should detect end of request according to HTTP specification - http://stackoverflow.com/questions/4824451/detect-end-of-http-request-body – Denys Kurochkin Sep 07 '16 at 16:20

2 Answers2

3

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.

Denys Kurochkin
  • 1,360
  • 1
  • 18
  • 34
0

Create a request wrapper which extends HttpServletRequestWrapper, which will override the getInputStream() which in turn return ServletInputStream , which has the safe read method. try that

VinuBibin
  • 679
  • 8
  • 19