Skip to content

Extend Request to support ByteBuf inputs #1952

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

Merged
merged 3 commits into from
Apr 15, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions client/src/main/java/org/asynchttpclient/DefaultRequest.java
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
*/
package org.asynchttpclient;

import io.netty.buffer.ByteBuf;
import io.netty.handler.codec.http.HttpHeaders;
import io.netty.handler.codec.http.cookie.Cookie;
import io.netty.resolver.NameResolver;
Expand Down Expand Up @@ -51,6 +52,7 @@ public class DefaultRequest implements Request {
private final @Nullable List<byte[]> compositeByteData;
private final @Nullable String stringData;
private final @Nullable ByteBuffer byteBufferData;
private final @Nullable ByteBuf byteBufData;
private final @Nullable InputStream streamData;
private final @Nullable BodyGenerator bodyGenerator;
private final List<Param> formParams;
Expand Down Expand Up @@ -79,6 +81,7 @@ public DefaultRequest(String method,
@Nullable List<byte[]> compositeByteData,
@Nullable String stringData,
@Nullable ByteBuffer byteBufferData,
@Nullable ByteBuf byteBufData,
@Nullable InputStream streamData,
@Nullable BodyGenerator bodyGenerator,
List<Param> formParams,
Expand All @@ -104,6 +107,7 @@ public DefaultRequest(String method,
this.compositeByteData = compositeByteData;
this.stringData = stringData;
this.byteBufferData = byteBufferData;
this.byteBufData = byteBufData;
this.streamData = streamData;
this.bodyGenerator = bodyGenerator;
this.formParams = formParams;
Expand Down Expand Up @@ -176,6 +180,11 @@ public List<Cookie> getCookies() {
return byteBufferData;
}

@Override
public @Nullable ByteBuf getByteBufData() {
return byteBufData;
}

@Override
public @Nullable InputStream getStreamData() {
return streamData;
Expand Down
6 changes: 6 additions & 0 deletions client/src/main/java/org/asynchttpclient/Request.java
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
*/
package org.asynchttpclient;

import io.netty.buffer.ByteBuf;
import io.netty.handler.codec.http.HttpHeaders;
import io.netty.handler.codec.http.cookie.Cookie;
import io.netty.resolver.NameResolver;
Expand Down Expand Up @@ -103,6 +104,11 @@ public interface Request {
*/
@Nullable ByteBuffer getByteBufferData();

/**
* @return the request's body ByteBuf (only non-null if it was set this way)
*/
@Nullable ByteBuf getByteBufData();

/**
* @return the request's body InputStream (only non-null if it was set this way)
*/
Expand Down
12 changes: 12 additions & 0 deletions client/src/main/java/org/asynchttpclient/RequestBuilderBase.java
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
*/
package org.asynchttpclient;

import io.netty.buffer.ByteBuf;
import io.netty.handler.codec.http.DefaultHttpHeaders;
import io.netty.handler.codec.http.HttpHeaders;
import io.netty.handler.codec.http.cookie.Cookie;
Expand Down Expand Up @@ -76,6 +77,7 @@ public abstract class RequestBuilderBase<T extends RequestBuilderBase<T>> {
protected @Nullable List<byte[]> compositeByteData;
protected @Nullable String stringData;
protected @Nullable ByteBuffer byteBufferData;
protected @Nullable ByteBuf byteBufData;
protected @Nullable InputStream streamData;
protected @Nullable BodyGenerator bodyGenerator;
protected @Nullable List<Param> formParams;
Expand Down Expand Up @@ -121,6 +123,7 @@ protected RequestBuilderBase(Request prototype, boolean disableUrlEncoding, bool
compositeByteData = prototype.getCompositeByteData();
stringData = prototype.getStringData();
byteBufferData = prototype.getByteBufferData();
byteBufData = prototype.getByteBufData();
streamData = prototype.getStreamData();
bodyGenerator = prototype.getBodyGenerator();
if (isNonEmpty(prototype.getFormParams())) {
Expand Down Expand Up @@ -361,6 +364,7 @@ public void resetNonMultipartData() {
byteData = null;
compositeByteData = null;
byteBufferData = null;
byteBufData = null;
stringData = null;
streamData = null;
bodyGenerator = null;
Expand Down Expand Up @@ -405,6 +409,12 @@ public T setBody(ByteBuffer data) {
return asDerivedType();
}

public T setBody(ByteBuf data) {
resetBody();
byteBufData = data;
return asDerivedType();
}

public T setBody(InputStream stream) {
resetBody();
streamData = stream;
Expand Down Expand Up @@ -586,6 +596,7 @@ private RequestBuilderBase<?> executeSignatureCalculator() {
rb.compositeByteData = compositeByteData;
rb.stringData = stringData;
rb.byteBufferData = byteBufferData;
rb.byteBufData = byteBufData;
rb.streamData = streamData;
rb.bodyGenerator = bodyGenerator;
rb.virtualHost = virtualHost;
Expand Down Expand Up @@ -647,6 +658,7 @@ public Request build() {
rb.compositeByteData,
rb.stringData,
rb.byteBufferData,
rb.byteBufData,
rb.streamData,
rb.bodyGenerator,
formParamsCopy,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
import org.asynchttpclient.netty.request.body.NettyBody;
import org.asynchttpclient.netty.request.body.NettyBodyBody;
import org.asynchttpclient.netty.request.body.NettyByteArrayBody;
import org.asynchttpclient.netty.request.body.NettyByteBufBody;
import org.asynchttpclient.netty.request.body.NettyByteBufferBody;
import org.asynchttpclient.netty.request.body.NettyCompositeByteArrayBody;
import org.asynchttpclient.netty.request.body.NettyDirectBody;
Expand Down Expand Up @@ -96,6 +97,8 @@ private NettyBody body(Request request) {
nettyBody = new NettyByteBufferBody(StringUtils.charSequence2ByteBuffer(request.getStringData(), bodyCharset));
} else if (request.getByteBufferData() != null) {
nettyBody = new NettyByteBufferBody(request.getByteBufferData());
} else if (request.getByteBufData() != null) {
nettyBody = new NettyByteBufBody(request.getByteBufData());
} else if (request.getStreamData() != null) {
nettyBody = new NettyInputStreamBody(request.getStreamData());
} else if (isNonEmpty(request.getFormParams())) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
/*
* Copyright (c) 2015-2023 AsyncHttpClient Project. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.asynchttpclient.netty.request.body;

import io.netty.buffer.ByteBuf;

public class NettyByteBufBody extends NettyDirectBody {

private final ByteBuf bb;
private final CharSequence contentTypeOverride;
private final long length;

public NettyByteBufBody(ByteBuf bb) {
this(bb, null);
}

public NettyByteBufBody(ByteBuf bb, CharSequence contentTypeOverride) {
this.bb = bb;
length = bb.readableBytes();
this.contentTypeOverride = contentTypeOverride;
}

@Override
public long getContentLength() {
return length;
}

@Override
public CharSequence getContentTypeOverride() {
return contentTypeOverride;
}

@Override
public ByteBuf byteBuf() {
return bb;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
/*
* Copyright (c) 2010-2012 Sonatype, Inc. All rights reserved.
*
* This program is licensed to you under the Apache License Version 2.0,
* and you may not use this file except in compliance with the Apache License Version 2.0.
* You may obtain a copy of the Apache License Version 2.0 at http://www.apache.org/licenses/LICENSE-2.0.
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the Apache License Version 2.0 is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the Apache License Version 2.0 for the specific language governing permissions and limitations there under.
*/
package org.asynchttpclient.request.body;

import io.github.artsok.RepeatedIfExceptionsTest;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.asynchttpclient.AbstractBasicTest;
import org.asynchttpclient.AsyncHttpClient;
import org.asynchttpclient.Response;
import org.eclipse.jetty.server.Request;
import org.eclipse.jetty.server.handler.AbstractHandler;

import java.io.IOException;
import java.nio.charset.Charset;
import java.time.Duration;
import java.util.Arrays;

import static org.asynchttpclient.Dsl.asyncHttpClient;
import static org.asynchttpclient.Dsl.config;
import static org.junit.jupiter.api.Assertions.assertEquals;

public class PutByteBufTest extends AbstractBasicTest {

private void put(String message) throws Exception {
ByteBuf byteBuf = Unpooled.wrappedBuffer(message.getBytes());
try (AsyncHttpClient client = asyncHttpClient(config().setRequestTimeout(Duration.ofSeconds(2)))) {
Response response = client.preparePut(getTargetUrl()).setBody(byteBuf).execute().get();
assertEquals(response.getStatusCode(), 200);
assertEquals(response.getResponseBody(), message);
}
}

@RepeatedIfExceptionsTest(repeats = 5)
public void testPutSmallBody() throws Exception {
put("Hello Test");
}

@RepeatedIfExceptionsTest(repeats = 5)
public void testPutBigBody() throws Exception {
byte[] array = new byte[2048];
Arrays.fill(array, (byte) 97);
String longString = new String(array, Charset.forName("UTF-8"));

put(longString);
}

@Override
public AbstractHandler configureHandler() throws Exception {
return new AbstractHandler() {

@Override
public void handle(String s, Request request, HttpServletRequest httpRequest, HttpServletResponse response) throws IOException {
int size = 1024;
if (request.getContentLength() > 0) {
size = request.getContentLength();
}
byte[] bytes = new byte[size];
if (bytes.length > 0) {
final int read = request.getInputStream().read(bytes);
response.getOutputStream().write(bytes, 0, read);
}

response.setStatus(200);
response.getOutputStream().flush();
}
};
}
}