Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

POST HTTP Body #99

Closed
hohl opened this issue Mar 9, 2014 · 15 comments
Closed

POST HTTP Body #99

hohl opened this issue Mar 9, 2014 · 15 comments
Assignees
Milestone

Comments

@hohl
Copy link

hohl commented Mar 9, 2014

How can I read the full HTTP body of the send request in my public Response serve(IHTTPSession session) { implementation?


(I've tried IOUtils.readFully(session.getInputStream(), -1, false) already but it looks like it always ends in a SocketTimeoutException.)

@melezov
Copy link

melezov commented Mar 16, 2014

+1, experiencing the same problem - consuming the session.getInputStream will never return -1 as end of stream, but rather throw

java.net.SocketTimeoutException: Read timed out

instead... Switched over to using .available() to get the stream length but this is an ugly hack.

@hohl
Copy link
Author

hohl commented Mar 21, 2014

Can you please give a small example about your work around? I'm not sure what you are meaning.

@thomashw
Copy link

You can do this very similarly to how the beginning of the parseBody(Map<String, String> files) method works. Retrieve the "content-length" from the headers, then read the input stream using "content-length" as the number of bytes to be read.

Integer contentLength = Integer.parseInt(session.getHeaders().get( "content-length" ));
byte[] buf = new byte[contentLength];
try
{
    session.getInputStream().read( buf, 0, contentLength );
    System.out.println( new String(buf) );
}
catch( IOException e2 )
{
}

It would be nice if NanoHTTPD did this for us. Maybe a pull request is in order.

@psh
Copy link
Contributor

psh commented Apr 24, 2014

I am always happy to accept pull requests - the proposed helper method sounds very testable too, so please include appropriate unit tests with the code change and I'll see about merging it.

@ghost
Copy link

ghost commented Apr 27, 2015

Quick hack to support reading text-based posts (e.g. JSON)
This is not good for large POSTs and I don't actually know Java.

Can someone see if they can apply this to the current tree? I couldn't get format-patch to output a clean patch so this is a bit hacked up

@@ -960,6 +928,7 @@ public abstract class NanoHTTPD {
          * @param files map to modify
          */
         void parseBody(Map<String, String> files) throws IOException, ResponseException;
+        String parsePost() throws IOException, ResponseException;
     }

     protected class HTTPSession implements IHTTPSession {
@@ -1089,6 +1058,30 @@ public abstract class NanoHTTPD {
         }

         @Override
+        public String parsePost() throws IOException, ResponseException {
+            long size;
+            if (headers.containsKey("content-length")) {
+                size = Integer.parseInt(headers.get("content-length"));
+            } else {
+                size = 0;
+            }
+            //http://stackoverflow.com/a/9133993/229631
+            ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
+
+            byte[] buffer = new byte[1024];
+            int len;
+            while ((len = inputStream.read(buffer)) != -1) {
+                outputStream.write(buffer, 0, len);
+            }
+
+            byte[] outputBytes = outputStream.toByteArray();
+            //todo: this will break with size > int.max
+            byte[] postBodyBytes = Arrays.copyOfRange(outputBytes, outputBytes.length - (int) size, outputBytes.length);
+
+            return new String(postBodyBytes);
+        }
+
+        @Override
         public void parseBody(Map<String, String> files) throws IOException, ResponseException {
             RandomAccessFile randomAccessFile = null;
             BufferedReader in = null;

@elonen
Copy link
Member

elonen commented May 10, 2015

Refactoring the first part of parseBody() into a separate function might be a good idea. It should probably work so that parseBody() would pass it the randomAccessFile, but one could as well ask it to read into a memory buffer.

If we decide to provide a request body => String helper, it should probably take character encoding into account. For example: Content-Type: application/x-www-form-urlencoded ; charset=UTF-8

@ghost
Copy link

ghost commented May 10, 2015 via email

@ghost
Copy link

ghost commented May 14, 2015

Can you comment on how plausible it would be to pull this out into something that could be extended/overridden by people, like https://github.com/NanoHttpd/nanohttpd/wiki/How-to-use-NanoHttpd?

I think that a getBody() that returned a String or Stream would be most useful inside NanoHTTPD itself, and then leave more complex operations (JSON parsing) to the implementer.

@elonen
Copy link
Member

elonen commented May 16, 2015

Yes, JSON parsing is definitely too specific a feature, but a getBodyAsString(int maxBytes) or something is probably such a common use case that providing it would be nice. The parsePost() example above looks like a good start, but a max limit on length is probably necessary as a security feature, and the function should respect charset in Content-Type header, as I wrote earlier.

Can you elaborate on the extendable/overridable question, or propose something about that @voltagex ?

@ritchieGitHub ritchieGitHub added this to the 2.3.0 milestone May 24, 2015
@ranjithsr
Copy link

How can i get the Request Payload data from IHTTPSession?
payload 1

I have an web application, which post the data through Request Payload(Ref: IMage).
How i have to get that xml content(Request Payload) through IHTTPSession?

@elonen
Copy link
Member

elonen commented May 30, 2015

@ranjithsr: You can call getInputStream() in your serve() function and read it from there. Alternatively, if you are using HTTP POST with content type other than "multipart/form-data" or "application/x-www-form-urlencoded" and know that your body is text, you can call parseBody() in serve() and fetch the body as a string from files.get("postData").

@fedotxxl
Copy link

+1. Please simplify getting content of POST request. Answers from http://stackoverflow.com/questions/22349772/retrieve-http-body-in-nanohttpd looks like dirty magic

@elonen
Copy link
Member

elonen commented Oct 13, 2015

@fedotxxl : I'm re-closing this, but if you have a concrete suggestion / question for a better API, feel free to submit a new issue or pull request.

@elonen elonen closed this as completed Oct 13, 2015
@tobiascapin
Copy link

You can do this very similarly to how the beginning of the parseBody(Map<String, String> files) method works. Retrieve the "content-length" from the headers, then read the input stream using "content-length" as the number of bytes to be read.

Integer contentLength = Integer.parseInt(session.getHeaders().get( "content-length" ));
byte[] buf = new byte[contentLength];
try
{
    session.getInputStream().read( buf, 0, contentLength );
    System.out.println( new String(buf) );
}
catch( IOException e2 )
{
}

It would be nice if NanoHTTPD did this for us. Maybe a pull request is in order.

I tried this code, but the payload is not fully copied to the buffer. It works only for small payloads.

@erikvanzijst
Copy link

I'm very late to the party, but I agree with the sentiment expressed in this ticket that it should be more intuitive to get the POST body either as a string, or by just consuming an InputStream.

I too lost a lot of time trying to consume the body only to bump into this closed issue that doesn't have a particularly good answer.

If this functionality is considered undesirable, then having a clear example snippet in the README would be very helpful.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

10 participants