Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
c679dc1
Add support for HTTP Client 5 (`HTTPHC5Impl`)
andreaslind01 Jul 22, 2026
acd67ec
Refactor `HTTPHC5Impl` to improve connection and timeout handling met…
andreaslind01 Jul 23, 2026
e72755d
Add support for DNS resolution and response decompression in HTTPHC5Impl
andreaslind01 Jul 23, 2026
de30d28
Refactor `DNSCacheManager` to simplify interface and integrate with `…
andreaslind01 Jul 23, 2026
0b533bd
Handle null `RequestConfig` in `HTTPHC5Impl` to ensure default config…
andreaslind01 Jul 23, 2026
fa4a038
Add caching and conditional requests support in `HTTPHC5Impl` using `…
andreaslind01 Jul 23, 2026
7556679
Add HTTP/2 support in `HTTPHC5Impl` with configurable HTTP version ha…
andreaslind01 Jul 23, 2026
cf1b9cf
Add unit tests for `HTTPHC5Impl` features including HTTP/2, caching, …
andreaslind01 Jul 23, 2026
6b6d09d
Add HTTP/2 support to `HTTPJavaImpl` with configurable version handli…
andreaslind01 Jul 23, 2026
3e86a0c
Add `httpVersion` to ignored properties in `JMeterTest`
andreaslind01 Jul 24, 2026
947dae7
Update `HTTPHC5Impl` to use `HttpVersionPolicy.NEGOTIATE` for HTTP/2 …
andreaslind01 Jul 24, 2026
12de7e9
Update dependencies to replace `httpcore5-h2` with `httpcore5` in `HT…
andreaslind01 Jul 24, 2026
6e74d4f
Add `sentBytes` calculation to `HTTPHC5Impl` and corresponding unit t…
andreaslind01 Jul 24, 2026
cdb95b9
Add `sentBytes` calculation to `HTTPJavaImpl` for GET and POST reques…
andreaslind01 Jul 27, 2026
72eccfe
Improve header handling in `HTTPJavaImpl` by preserving security head…
andreaslind01 Jul 27, 2026
546b2a0
Add connect time measurement to `HTTPJavaImpl` and `HTTPHC5Impl` with…
andreaslind01 Jul 27, 2026
eef1096
Add connect time measurement for HTTP/2 in `HTTPJavaImpl` with unit t…
andreaslind01 Jul 28, 2026
6249443
Add HTTP/2 reason phrase handling in `HTTPJavaImpl` with unit tests
andreaslind01 Jul 28, 2026
1bf6009
Reorder HTTP version options in GUI components for consistency
andreaslind01 Jul 28, 2026
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
5 changes: 3 additions & 2 deletions bin/jmeter.properties
Original file line number Diff line number Diff line change
Expand Up @@ -378,8 +378,9 @@ remote_hosts=127.0.0.1
#httpclient.timeout=0
# 0 == no timeout

# Set the http version (defaults to 1.1)
#httpclient.version=1.1 (or use the parameter http.protocol.version)
# Set the default HTTP version for HttpClient5 and Java samplers when HTTP Version is empty
# Valid values are HTTP/1.1 and HTTP/2 (defaults to HTTP/1.1)
#httpclient.version=HTTP/1.1

# Define characters per second > 0 to emulate slow connections
#httpclient.socket.http.cps=0
Expand Down
1 change: 1 addition & 0 deletions src/bom-thirdparty/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,7 @@ dependencies {
because("User might still rely on commons-text")
}
api("org.apache.httpcomponents.client5:httpclient5:5.5.1")
api("org.apache.httpcomponents.core5:httpcore5:5.3.4")
api("org.apache.httpcomponents:httpasyncclient:4.1.5")
api("org.apache.httpcomponents:httpclient:4.5.14")
api("org.apache.httpcomponents:httpcore-nio:4.4.16")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -473,6 +473,7 @@ html_assertion_title=HTML Assertion
html_extractor_title=CSS Selector Extractor
html_extractor_type=CSS Selector Extractor Implementation
http_implementation=Implementation:
http_version=HTTP Version:
html_report=Generate HTML report
http_response_code=HTTP response code
http_url_rewriting_modifier_title=HTTP URL Re-writing Modifier
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
#

about=Über Apache JMeter
http_version=HTTP-Version\:
add=Hinzufügen
add_as_child=Als ein Kind hinzufügen
add_parameter=Variable hinzufügen
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -273,6 +273,7 @@ html_assertion_file=Escribir el reporte JTidy en fichero
html_assertion_label=Aserción HTML
html_assertion_title=Aserción HTML
http_implementation=Implementación HTTP\:
http_version=Versión HTTP\:
http_response_code=código de respuesta HTTP
http_url_rewriting_modifier_title=Modificador de re-escritura HTTP URL
http_user_parameter_modifier=Modificador de Parámetro de Usuario HTTP
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -467,6 +467,7 @@ html_assertion_title=Assertion HTML
html_extractor_title=Extracteur par Sélecteur CSS
html_extractor_type=Implémentation de l'extracteur Sélecteur CSS
http_implementation=Implémentation \:
http_version=Version HTTP \:
html_report=Générer le rapport HTML
http_response_code=Code de réponse HTTP
http_url_rewriting_modifier_title=Transcripteur d'URL HTTP
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -176,6 +176,7 @@ grouping_store_first_only=各グループの最初のサンプラーだけ保存
header_manager_title=HTTP ヘッダマネージャ
headers_stored=ヘッダーマネージャに保存されているヘッダ
help=ヘルプ
http_version=HTTP バージョン\:
http_response_code=HTTP応答コード
http_url_rewriting_modifier_title=HTTP URL-Rewriting 修飾子
http_user_parameter_modifier=HTTPユーザーパラメータの変更
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -471,6 +471,7 @@ html_assertion_title=HTML Assertion
html_extractor_title=CSS Selector 추출기
html_extractor_type=CSS Selector 추출기 구현
http_implementation=구현\:
http_version=HTTP 버전\:
html_report=HTML 보고서 생성
http_response_code=HTTP 응답 코드
http_url_rewriting_modifier_title=HTTP URL Re-writing Modifier
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ graph_results_deviation=Avvik
graph_results_title=Graf resultater
headers_stored=Headere lagret hos headermanager
help=Hjelp
http_version=HTTP-versjon\:
infinite=Uendelig
interleave_control_title=Vekslende kontroller
iterator_num=Løkketeller\:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
#

about=O programie Apache JMeter
http_version=Wersja HTTP\:
action_check_message=Aktualnie jest przeprowadzany test, zatrzymaj albo wyłącz test, aby uruchomić to polecenie
action_check_title=Test uruchomiony
active_total_threads_tooltip=Uruchamianie wątków / całkowita liczba wątków do uruchomienia
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -261,6 +261,7 @@ html_assertion_file=Escrever relatório do JTidy em arquivo
html_assertion_label=Asserção HTML
html_assertion_title=Asserção HTML
http_implementation=Implementação\:
http_version=Versão HTTP\:
http_response_code=Código da Resposta HTTP
http_url_rewriting_modifier_title=Modificador de Re-escrita de URL HTTP
http_user_parameter_modifier=Modificador de Parâmetros HTTP do Usuário
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -246,6 +246,7 @@ html_assertion_file=JTidy raporunu dosyaya yaz
html_assertion_label=HTML Doğrulama
html_assertion_title=HTML Doğrulama
http_implementation=Uygulaması\:
http_version=HTTP sürümü\:
http_response_code=HTTP cevap kodu
http_url_rewriting_modifier_title=HTTP URL Yeniden Yazma Niteleyicisi
http_user_parameter_modifier=HTTP Kullanıcı Parametresi Niteleyicisi
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -433,6 +433,7 @@ html_assertion_title=HTML断言
html_extractor_title=CSS/JQuery提取器
html_extractor_type=CSS 选择器提取器实现
http_implementation=实现:
http_version=HTTP 版本:
http_response_code=HTTP响应代码
http_url_rewriting_modifier_title=HTTP URL 重写修饰符
http_user_parameter_modifier=HTTP 用户参数修饰符
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -206,6 +206,7 @@ headers_stored=標頭管理員中儲存的標頭資料
help=輔助說明
html_assertion_label=HTML 驗證
html_assertion_title=HTML 驗證
http_version=HTTP 版本:
http_response_code=HTTP 回應代碼
http_url_rewriting_modifier_title=HTTP URL 重導修飾詞
http_user_parameter_modifier=HTTP 使用者參數修飾詞
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -385,6 +385,7 @@ public void GUIComponents2(GuiComponentHolder componentHolder) throws Exception
// TODO: support expressions?
IGNORED_PROPERTIES.add(HTTPSamplerBaseSchema.INSTANCE.getIpSourceType());
IGNORED_PROPERTIES.add(HTTPSamplerBaseSchema.INSTANCE.getImplementation());
IGNORED_PROPERTIES.add(HTTPSamplerBaseSchema.INSTANCE.getHttpVersion());
// TODO: support expressions in UrlConfigGui
IGNORED_PROPERTIES.add(HTTPSamplerBaseSchema.INSTANCE.getFollowRedirects());
IGNORED_PROPERTIES.add(HTTPSamplerBaseSchema.INSTANCE.getAutoRedirects());
Expand Down
2 changes: 2 additions & 0 deletions src/protocol/http/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,8 @@ dependencies {
exclude("com.google.code.findbugs", "jsr305")
}
implementation("dnsjava:dnsjava")
implementation("org.apache.httpcomponents.client5:httpclient5")
implementation("org.apache.httpcomponents.core5:httpcore5")
implementation("org.apache.httpcomponents:httpmime")
implementation("org.apache.httpcomponents:httpcore")
implementation("org.brotli:dec")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,7 @@ public class HttpDefaultsGui extends AbstractConfigGui {
private JTextField proxyUser;
private JPasswordField proxyPass;
private final JComboBox<String> httpImplementation = new JComboBox<>(HTTPSamplerFactory.getImplementations());
private final JComboBox<String> httpVersion = new JComboBox<>(new String[] {"HTTP/1.1", "HTTP/2", ""});
private JTextField connectTimeOut;
private JTextField responseTimeOut;

Expand Down Expand Up @@ -152,6 +153,7 @@ public void modifyTestElement(TestElement config) {
}

config.set(httpSchema.getImplementation(), String.valueOf(httpImplementation.getSelectedItem()));
config.set(httpSchema.getHttpVersion(), String.valueOf(httpVersion.getSelectedItem()));
}

@Override
Expand All @@ -169,6 +171,7 @@ public void configure(TestElement el) {
HTTPSamplerBaseSchema httpSchema = HTTPSamplerBaseSchema.INSTANCE;
sourceIpType.setSelectedIndex(samplerBase.get(httpSchema.getIpSourceType()));
httpImplementation.setSelectedItem(samplerBase.getString(httpSchema.getImplementation()));
httpVersion.setSelectedItem(samplerBase.getString(httpSchema.getHttpVersion()));
}

private void init() { // WARNING: called from ctor so must not be overridden (i.e. must be private or final)
Expand Down Expand Up @@ -329,6 +332,8 @@ protected final JPanel getImplementationPanel(){
implPanel.add(new JLabel(JMeterUtils.getResString("http_implementation"))); // $NON-NLS-1$
httpImplementation.addItem("");// $NON-NLS-1$
implPanel.add(httpImplementation);
implPanel.add(new JLabel(JMeterUtils.getResString("http_version"))); // $NON-NLS-1$
implPanel.add(httpVersion);
return implPanel;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -245,6 +245,55 @@ public void saveDetails(HttpResponse method, HTTPSampleResult res) {
}
}

/**
* Save the Last-Modified, Etag, and Expires headers if the result is
* cacheable. Version for Apache HttpClient 5 implementation.
*
* @param response response to extract header information from
* @param res result to decide if result is cacheable
*/
public void saveDetails(org.apache.hc.core5.http.ClassicHttpResponse response, HTTPSampleResult res) {
final String varyHeader = getHeader(response, HTTPConstants.VARY);
if (isCacheable(res, varyHeader)) {
String lastModified = getHeader(response, HTTPConstants.LAST_MODIFIED);
String expires = getHeader(response, HTTPConstants.EXPIRES);
String etag = getHeader(response, HTTPConstants.ETAG);
String cacheControl = getHeader(response, HTTPConstants.CACHE_CONTROL);
String date = getHeader(response, HTTPConstants.DATE);
if (anyNotBlank(lastModified, expires, etag, cacheControl)) {
setCache(lastModified, cacheControl, expires, etag,
res.getUrlAsString(), date, getVaryHeader(varyHeader, asHeaders(res.getRequestHeaders())));
}
}
}

/**
* Save the Last-Modified, Etag, and Expires headers if the result is
* cacheable. Version for Java HttpClient implementation.
*
* @param response response to extract header information from
* @param res result to decide if result is cacheable
*/
public void saveDetails(java.net.http.HttpResponse<?> response, HTTPSampleResult res) {
final String varyHeader = response.headers().firstValue(HTTPConstants.VARY).orElse(null);
if (isCacheable(res, varyHeader)) {
String lastModified = response.headers().firstValue(HTTPConstants.LAST_MODIFIED).orElse(null);
String expires = response.headers().firstValue(HTTPConstants.EXPIRES).orElse(null);
String etag = response.headers().firstValue(HTTPConstants.ETAG).orElse(null);
String cacheControl = response.headers().firstValue(HTTPConstants.CACHE_CONTROL).orElse(null);
String date = response.headers().firstValue(HTTPConstants.DATE).orElse(null);
if (anyNotBlank(lastModified, expires, etag, cacheControl)) {
setCache(lastModified, cacheControl, expires, etag,
res.getUrlAsString(), date, getVaryHeader(varyHeader, asHeaders(res.getRequestHeaders())));
}
}
}

private static String getHeader(org.apache.hc.core5.http.HttpMessage message, String name) {
org.apache.hc.core5.http.Header header = message.getFirstHeader(name);
return header == null ? null : header.getValue();
}

// helper method to save the cache entry
private void setCache(String lastModified, String cacheControl, String expires,
String etag, String url, String date, Map.Entry<String, String> varyHeader) {
Expand Down Expand Up @@ -410,6 +459,29 @@ public void setHeaders(URL url, HttpRequestBase request) {
}
}

/**
* Check the cache, and if there is a match, set conditional request headers.
*
* @param url URL to look up in cache
* @param request request where to set the headers
*/
public void setHeaders(URL url, org.apache.hc.core5.http.ClassicHttpRequest request) {
CacheEntry entry = getEntry(url.toString(), asHeaders(request.getHeaders()));
if (log.isDebugEnabled()) {
log.debug("setHeaders for HTTP Method:{}(HC5) URL:{} Entry:{}", request.getMethod(), url, entry);
}
if (entry != null) {
String lastModified = entry.getLastModified();
if (lastModified != null) {
request.setHeader(HTTPConstants.IF_MODIFIED_SINCE, lastModified);
}
String etag = entry.getEtag();
if (etag != null) {
request.setHeader(HTTPConstants.IF_NONE_MATCH, etag);
}
}
}

/**
* Check the cache, and if there is a match, set the headers:
* <ul>
Expand Down Expand Up @@ -460,6 +532,17 @@ public boolean inCache(URL url, Header[] allHeaders) {
return entryStillValid(url, getEntry(url.toString(), allHeaders));
}

/**
* Check whether the URL has a valid entry for the supplied HttpClient 5 request headers.
*
* @param url URL to look up in cache
* @param allHeaders request headers
* @return {@code true} if the matching entry has not expired
*/
public boolean inCache(URL url, org.apache.hc.core5.http.Header[] allHeaders) {
return entryStillValid(url, getEntry(url.toString(), asHeaders(allHeaders)));
}

public boolean inCache(URL url, org.apache.jmeter.protocol.http.control.Header[] allHeaders) {
return entryStillValid(url, getEntry(url.toString(), asHeaders(allHeaders)));
}
Expand All @@ -484,6 +567,14 @@ private static Header[] asHeaders(String allHeaders) {
return result.toArray(new Header[result.size()]);
}

private static Header[] asHeaders(org.apache.hc.core5.http.Header[] allHeaders) {
Header[] result = new Header[allHeaders.length];
for (int i = 0; i < allHeaders.length; i++) {
result[i] = new BasicHeader(allHeaders[i].getName(), allHeaders[i].getValue());
}
return result;
}

private static class HeaderAdapter implements Header {

private final org.apache.jmeter.protocol.http.control.Header delegate;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@ public class HttpTestSampleGui extends AbstractSamplerGui {
private JTextField proxyUser;
private JPasswordField proxyPass;
private final JComboBox<String> httpImplementation = new JComboBox<>(HTTPSamplerFactory.getImplementations());
private final JComboBox<String> httpVersion = new JComboBox<>(new String[] {"HTTP/1.1", "HTTP/2", ""});
private JTextField connectTimeOut;
private JTextField responseTimeOut;

Expand Down Expand Up @@ -135,6 +136,7 @@ public void configure(TestElement element) {
if (!isAJP) {
sourceIpType.setSelectedIndex(samplerBase.getIpSourceType());
httpImplementation.setSelectedItem(samplerBase.getString(httpSchema.getImplementation()));
httpVersion.setSelectedItem(samplerBase.getHttpVersion());
}
}

Expand Down Expand Up @@ -179,6 +181,9 @@ public void modifyTestElement(TestElement sampler) {
String selectedImplementation = String.valueOf(httpImplementation.getSelectedItem());
samplerBase.set(httpSchema.getImplementation(),
StringUtilities.isBlank(selectedImplementation) ? null : selectedImplementation);
String selectedHttpVersion = String.valueOf(httpVersion.getSelectedItem());
samplerBase.set(httpSchema.getHttpVersion(),
StringUtilities.isBlank(selectedHttpVersion) ? null : selectedHttpVersion);
}
}

Expand Down Expand Up @@ -349,6 +354,8 @@ protected final JPanel getImplementationPanel(){
implPanel.add(new JLabel(JMeterUtils.getResString("http_implementation"))); // $NON-NLS-1$
httpImplementation.addItem("");// $NON-NLS-1$
implPanel.add(httpImplementation);
implPanel.add(new JLabel(JMeterUtils.getResString("http_version"))); // $NON-NLS-1$
implPanel.add(httpVersion);
return implPanel;
}

Expand Down
Loading
Loading