ReactiveX / RxNetty

Reactive Extension (Rx) Adaptor for Netty
Apache License 2.0
1.38k stars 254 forks source link

Question on POST for 0.5.X #538

Open eleduardo opened 8 years ago

eleduardo commented 8 years ago

Hi sorry if this is documented somewhere but I don't seem to find an example for a POST on 0.5.X the 0.4 way of doing it seems to have been removed.

If I do this HttpClientRequest request = client.createPost("/foo/bar").writeBytesContent(Observable.just("ABCD".getBytes()));

I put a tunnel to capture the request and the body always has the size of the payload pre-pended! I am wondering if it is because the client wants to do chunking?

I tried "writeContent", "writeBytesContent", "writeStringContent" but I don't know what is causing the issue. Is this a bug or am I doing something wrong?

If it is chunking how can you tell the client not to send chunks?

Here is a capture of the request

POST /ffoo/bar HTTP/1.1 Content-Type: text/plain transfer-encoding: chunked host: localhost:8200

4 ABCD 0

jamesgorman2 commented 8 years ago

Hi Eleduardo,

a good place to start (not in the examples though!) is HttpClientTest

The client (and server) chunk-encodes by default. You can disable chunk-encoding by specifying the content-length header.

Tests for un-chunked POSTs start at #testRequestWithContentLengthReturnsRawBody().

(if you want to look the code, you'll do best to load RxNetty into an IDE to follow the code into HttpClientRule to see what it is doing)

eleduardo commented 8 years ago

Thanks James!

That worked... in 0.4 it was a little bit simpler...

It does make sense to chunk the content when the payload comes from an observable but, would there be any chance to add a signature that takes the raw content instead of an observable and it performs the calculation for you?

jamesgorman2 commented 8 years ago

Probably not (easily). @NiteshKant can correct this, but my reading is since the data transformations are handled on the content Observable in the TcpClient one the event loop (cf AllocatingTransformer for more on why this is so), getting a consistent API is hard. By this I mean that a user should only specify the transformations in one place (both in their code and in the API) so they can't get it wrong, and specify things to avoid memory bloat. There may be ways to do it so that things execute on the event loop and headers get written in the write place but it looks like that would require some pretty major work.

If you can't get around requiring un-chunked messages, I'd recommend writing a utility method to write your response as bytes with the size header, something like:

public <I, O> Observable<HttpClientResponse<O>> writeAsSingleMessage(HttpClientRequest<I, O> request , String s, Charset charset) {
  byte[] bs = s.getBytes(charset);
  request.setHeader(HttpHeaderNames.CONTENT_LENGTH, bs.length);
  return request.writeBytesContent(bs);
}
NiteshKant commented 8 years ago

@eleduardo as @jamesgorman2 suggested, the method to just use a single item as content is pretty straightforward, so I do not see a reason to expand the API for this special case. It certainly would be useful to add an example for HTTP Post!