HttpRequest returning null entity, cannot extract

2019-08-08 10:04发布

问题:

I'm trying to parse an HTTP request using the apache httpcore components and want to grab the body of the request. It looks like the default DefaultHttpRequestParser doesn't parse the body/entity from its input stream. Is there a class that will do this?

Unfortunately I can't use the entire stack and need to pull the request straight from this input stream.

My parsing code is below. Looking at some of the other answers it appears that the body of the request should be available as an entity. However, every time I try to get at the entity it is null.

Debugging I see that the buffer has read but not used the body and that DefaultHttpRequestParser seems to just read the header. Is there a parse I should be using to parse the entire input?

    InputStream is = socket.getInputStream();
    HttpTransportMetricsImpl metrics = new HttpTransportMetricsImpl();
    SessionInputBufferImpl buf = new SessionInputBufferImpl(metrics, 2048);
    buf.bind(is);

    DefaultHttpRequestParser reqParser = new DefaultHttpRequestParser(buf);
    HttpRequest req = reqParser.parse();
    if (req instanceof HttpEntityEnclosingRequest) {
        entity = ((HttpEntityEnclosingRequest)query).getEntity();
        //... entity is always null

If I read the input stream I end up with:

POST / HTTP/1.1
User-Agent: curl/Q.XX.0 (linux-gnu) libcurl/Q.XX.0 OpenSSL/X.Y.Z zlib/A.B.C.D libidn/E.FF librtmp/G.H
Host: localhost:8088
Accept: */*
Content-Length: 333
Content-Type: multipart/form-data; boundary=----------------------------39203c7982df

------------------------------39203c7982df
Content-Disposition: form-data; name="fileupload"; filename="grun.sh"
Content-Type: application/octet-stream

#!/bin/bash -x
java -classpath lib/antlr-4.4-complete.jar:build/classes org.antlr.v4.runtime.misc.TestRig Typegroup "AHI" -tree

------------------------------39203c7982df--

[Update] Oleg has a good answer, but can I associate the body with the request or do I now need to pass two things around, the body and the stream? I'll be looking into

I got the following to work, but it's deprecated in the latest release.

        ...
        HttpEntityEnclosingRequest ereq = (HttpEntityEnclosingRequest) req;
        @SuppressWarnings("deprecation")
        EntityDeserializer ed = 
           new EntityDeserializer(new LaxContentLengthStrategy());
        @SuppressWarnings("deprecation")//ack!
        HttpEntity ent = ed.deserialize(buf, req);
        ereq.setEntity(ent);
        return ereq;

Combining Oleg's solution with the above I ended up with:

            HttpEntityEnclosingRequest ereq = (HttpEntityEnclosingRequest) req;

            ContentLengthStrategy contentLengthStrategy =
                        StrictContentLengthStrategy.INSTANCE;
            long len = contentLengthStrategy.determineLength(req);
            InputStream contentStream = null;
            if (len == ContentLengthStrategy.CHUNKED) {
                contentStream = new ChunkedInputStream(buf);
            } else if (len == ContentLengthStrategy.IDENTITY) {
                contentStream = new IdentityInputStream(buf);
            } else {
                contentStream = new ContentLengthInputStream(buf, len);
            }
            BasicHttpEntity ent = new BasicHttpEntity();
            ent.setContent(contentStream);
            ereq.setEntity(ent);
            return ereq;

回答1:

InputStream is = socket.getInputStream();
HttpTransportMetricsImpl metrics = new HttpTransportMetricsImpl();
SessionInputBufferImpl buf = new SessionInputBufferImpl(metrics, 2048);
buf.bind(is);

DefaultHttpRequestParser reqParser = new DefaultHttpRequestParser(buf);
HttpRequest req = reqParser.parse();
InputStream contentStream = null;
if (req instanceof HttpEntityEnclosingRequest) {
    ContentLengthStrategy contentLengthStrategy = StrictContentLengthStrategy.INSTANCE;
    long len = contentLengthStrategy.determineLength(req);
    if (len == ContentLengthStrategy.CHUNKED) {
        contentStream = new ChunkedInputStream(buf);
    } else if (len == ContentLengthStrategy.IDENTITY) {
        contentStream = new IdentityInputStream(buf);
    } else {
        contentStream = new ContentLengthInputStream(buf, len);
    }
}
// Do something useful with the content stream (if non null)

Message parsers in HttpCore parse message heads only. However, one can proceed reading from the session input buffer and read message body content until the end of message (depending on the delineator used)