Skip to content
Open
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
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2017-2025 VMware, Inc. or its affiliates, All Rights Reserved.
* Copyright (c) 2017-2026 VMware, Inc. or its affiliates, 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.
Expand Down Expand Up @@ -49,7 +49,7 @@ public interface HttpClientForm {

/**
* Should file attributes be cleaned and eventually removed from disk.
* Default to false.
* Default to true.
*
* @param clean true if cleaned on termination (successful or failed)
*
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2011-2025 VMware, Inc. or its affiliates, All Rights Reserved.
* Copyright (c) 2011-2026 VMware, Inc. or its affiliates, 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.
Expand Down Expand Up @@ -53,6 +53,7 @@ final class HttpClientFormEncoder extends HttpPostRequestEncoder
HttpDataFactory newFactory;
boolean cleanOnTerminate;
Charset newCharset;
@Nullable HttpClientFormEncoder nextEncoder;
boolean newMultipart;
EncoderMode newMode;

Expand Down Expand Up @@ -101,6 +102,10 @@ public HttpContent readChunk(ByteBufAllocator allocator) throws Exception {

@Override
public HttpClientForm attr(String name, String value) {
HttpClientFormEncoder encoder = applyChanges(request);
if (encoder != this) {
return encoder.attr(name, value);
}
try {
addBodyAttribute(name, value);
}
Expand All @@ -112,19 +117,31 @@ public HttpClientForm attr(String name, String value) {

@Override
public HttpClientForm charset(Charset charset) {
HttpClientFormEncoder encoder = currentEncoder();
if (encoder != this) {
return encoder.charset(charset);
}
this.newCharset = Objects.requireNonNull(charset, "charset");
this.needNewEncoder = true;
return this;
}

@Override
public HttpClientForm cleanOnTerminate(boolean clean) {
HttpClientFormEncoder encoder = currentEncoder();
if (encoder != this) {
return encoder.cleanOnTerminate(clean);
}
this.cleanOnTerminate = clean;
return this;
}

@Override
public HttpClientForm factory(HttpDataFactory factory) {
HttpClientFormEncoder encoder = currentEncoder();
if (encoder != this) {
return encoder.factory(factory);
}
if (!getBodyListAttributes().isEmpty()) {
throw new IllegalStateException("Cannot set a new HttpDataFactory after " +
"starting appending Parts, call factory(f) at the earliest occasion" +
Expand Down Expand Up @@ -152,6 +169,10 @@ public HttpClientForm file(String name,
String filename,
File file,
@Nullable String contentType) {
HttpClientFormEncoder encoder = applyChanges(request);
if (encoder != this) {
return encoder.file(name, filename, file, contentType);
}
Objects.requireNonNull(name, "name");
Objects.requireNonNull(file, "file");
Objects.requireNonNull(filename, "filename");
Expand Down Expand Up @@ -184,6 +205,10 @@ public HttpClientForm file(String name,
String filename,
InputStream stream,
@Nullable String contentType) {
HttpClientFormEncoder encoder = applyChanges(request);
if (encoder != this) {
return encoder.file(name, filename, stream, contentType);
}
Objects.requireNonNull(name, "name");
Objects.requireNonNull(stream, "stream");
try {
Expand Down Expand Up @@ -226,6 +251,10 @@ public HttpClientForm files(String name,
File[] files,
String[] contentTypes,
boolean[] textFiles) {
HttpClientFormEncoder encoder = applyChanges(request);
if (encoder != this) {
return encoder.files(name, files, contentTypes, textFiles);
}
try {
addBodyFileUploads(name, files, contentTypes, textFiles);
}
Expand All @@ -237,14 +266,22 @@ public HttpClientForm files(String name,

@Override
public HttpClientForm encoding(EncoderMode mode) {
HttpClientFormEncoder encoder = currentEncoder();
if (encoder != this) {
return encoder.encoding(mode);
}
this.newMode = Objects.requireNonNull(mode, "mode");
this.needNewEncoder = true;
return this;
}

@Override
public HttpClientForm multipart(boolean isMultipart) {
this.needNewEncoder = isChunked() != isMultipart;
HttpClientFormEncoder encoder = currentEncoder();
if (encoder != this) {
return encoder.multipart(isMultipart);
}
this.needNewEncoder |= isMultipart() != isMultipart;
this.newMultipart = isMultipart;
return this;
}
Expand All @@ -257,6 +294,10 @@ public HttpClientForm textFile(String name, File file) {

@Override
public HttpClientForm textFile(String name, File file, @Nullable String contentType) {
HttpClientFormEncoder encoder = applyChanges(request);
if (encoder != this) {
return encoder.textFile(name, file, contentType);
}
try {
addBodyFileUpload(name, file, contentType, true);
}
Expand All @@ -276,6 +317,10 @@ public HttpClientForm textFile(String name, InputStream stream) {
public HttpClientForm textFile(String name,
InputStream stream,
@Nullable String contentType) {
HttpClientFormEncoder encoder = applyChanges(request);
if (encoder != this) {
return encoder.textFile(name, stream, contentType);
}
Objects.requireNonNull(name, "name");
Objects.requireNonNull(stream, "stream");
try {
Expand Down Expand Up @@ -310,7 +355,21 @@ public void run() {
cleanFiles();
}

@Override
public void cleanFiles() {
HttpClientFormEncoder encoder = currentEncoder();
if (encoder != this) {
encoder.cleanFiles();
}
else {
super.cleanFiles();
}
}

final HttpClientFormEncoder applyChanges(HttpRequest request) {
if (nextEncoder != null) {
return nextEncoder.applyChanges(request);
}
if (!needNewEncoder) {
return this;
}
Expand All @@ -322,6 +381,8 @@ final HttpClientFormEncoder applyChanges(HttpRequest request) {
newCharset,
newMode);

encoder.cleanOnTerminate = cleanOnTerminate;
nextEncoder = encoder;
encoder.setBodyHttpDatas(getBodyListAttributes());

needNewEncoder = false;
Expand All @@ -333,6 +394,14 @@ final HttpClientFormEncoder applyChanges(HttpRequest request) {
}
}

private HttpClientFormEncoder currentEncoder() {
HttpClientFormEncoder encoder = this;
while (encoder.nextEncoder != null) {
encoder = encoder.nextEncoder;
}
return encoder;
}

static final Map<Pattern, String> percentEncodings = new HashMap<>();
static final String DEFAULT_BINARY_CONTENT_TYPE =
"application/octet-stream";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1154,9 +1154,10 @@ public void subscribe(CoreSubscriber<? super Void> s) {
@SuppressWarnings("FutureReturnValueIgnored")
void _subscribe(CoreSubscriber<? super Void> s) {
HttpDataFactory df = DEFAULT_FACTORY;
HttpClientFormEncoder encoder = null;

try {
HttpClientFormEncoder encoder = new HttpClientFormEncoder(df,
encoder = new HttpClientFormEncoder(df,
parent.nettyRequest,
false,
HttpConstants.DEFAULT_CHARSET,
Expand Down Expand Up @@ -1227,7 +1228,12 @@ void _subscribe(CoreSubscriber<? super Void> s) {
}
catch (Throwable e) {
Exceptions.throwIfJvmFatal(e);
df.cleanRequestHttpData(parent.nettyRequest);
if (encoder != null) {
encoder.cleanFiles();
}
else {
df.cleanRequestHttpData(parent.nettyRequest);
}
s.onError(Exceptions.unwrap(e));
}
}
Expand Down
Loading