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
38 changes: 36 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -237,6 +237,39 @@ The available profiles are:
- **Legacy / Older Systems** (`legacy`)
- **Browser-like (Custom)** (`browser-like-custom`) (persists per-sampler toggles below)

You can also define additional profiles in `user.properties` / `jmeter.properties`.
Custom profiles are loaded by both the GUI and non-GUI runtime, so the same profile
works in local, CLI, and distributed test runs.

Example:

```properties
blazemeter.http.profiles.mobile-h3.label=Mobile H3 Conservative
blazemeter.http.profiles.mobile-h3.extends=browser-like
blazemeter.http.profiles.mobile-h3.enableHttp3=true
blazemeter.http.profiles.mobile-h3.enableHttp2=true
blazemeter.http.profiles.mobile-h3.enableHttp1=true
blazemeter.http.profiles.mobile-h3.happyEyeballsDelayMs=500
blazemeter.http.profiles.mobile-h3.http3BrokenCooldownMs=600000
```

Profile IDs may contain lowercase letters, digits, `_`, and `-`. If `extends` is omitted,
the custom profile inherits from `browser-like`. Supported fields are:

`label`, `extends`, `enableHttp3`, `enableHttp2`, `enableHttp1`, `alpnEnabled`,
`fallbackEnabled`, `protocolErrorFallbackEnabled`, `altSvcCacheEnabled`,
`http1OnlyCacheEnabled`, `h2cCacheEnabled`, `http2PriorKnowledge`,
`h2cUpgradeEnabled`, `happyEyeballsDelayMs`, `http3BrokenCooldownMs`,
`http1OnlyCooldownMs`, and `h2cCacheTtlMs`.

For larger profile sets, put the same properties in a separate file and reference it:

```properties
blazemeter.http.profiles.file=/path/to/http-profiles.properties
```

Profile values defined directly in JMeter properties override values loaded from that file.


<a id="readme-client-protocols"></a>
#### Client Behavior → Protocols / Fallback / Cache / Timing
Expand Down Expand Up @@ -391,6 +424,8 @@ Restart JMeter after changing JMeter properties that are applied when affected c
| **blazemeter.http.maxConcurrentAsyncInController** | Default concurrency cap inside **`bzm - HTTP Async Controller`** when parallel limiting is unchecked | 100 |
| **HTTPSampler.response_timeout** | Default response timeout (ms) when the sampler defines none | 0 |
| **http.post_add_content_type_if_missing** | Add Content-Type header if missing? | false |
| **blazemeter.http.profile** | Default client behavior profile when a sampler does not define one | browser-like |
| **blazemeter.http.profiles.file** | Optional `.properties` file containing custom profile definitions | |
| **blazemeter.http.enableHttp3** | Enable HTTP/3 support (Alt-Svc + QUIC) | profile |
| **blazemeter.http.enableHttp2** | Enable HTTP/2 support | profile |
| **blazemeter.http.enableHttp1** | Enable HTTP/1.1 support | profile |
Expand All @@ -403,7 +438,7 @@ Restart JMeter after changing JMeter properties that are applied when affected c
| **blazemeter.http.altSvcCacheEnabled** | Enable Alt-Svc cache for HTTP/3 discovery | profile |
| **blazemeter.http.http1OnlyCacheEnabled** | Enable HTTP/1.1-only cache for HTTPS origins | profile |
| **blazemeter.http.h2cCacheEnabled** | Enable H2C cache for cleartext origins | profile |
| **blazemeter.http.h2cUpgradeEnabled** | Enable **H2C Upgrade (HTTP/1.1 Upgrade)** | false |
| **blazemeter.http.h2cUpgradeEnabled** | Enable **H2C Upgrade (HTTP/1.1 Upgrade)** | profile |
| **blazemeter.http.h2cCacheTtlMs** | H2C cache TTL in milliseconds | profile |
| **blazemeter.http.http1OnlyCooldownMs** | HTTP/1.1-only cache TTL in milliseconds | profile |
| **blazemeter.http.http3BrokenCooldownMs** | Cooldown before retrying HTTP/3 after failures (ms) | profile |
Expand Down Expand Up @@ -432,4 +467,3 @@ Artifacts land under **`target/`**. Compilation uses the **`jmeter.version`** de
## License

Distributed under the **Apache License 2.0**. See **`LICENSE`** in this repository.

218 changes: 218 additions & 0 deletions src/main/java/com/blazemeter/jmeter/http2/core/HTTP2ClientProfile.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,218 @@
package com.blazemeter.jmeter.http2.core;

public final class HTTP2ClientProfile {

private final String id;
private final String label;
private final boolean enableHttp3;
private final boolean enableHttp2;
private final boolean enableHttp1;
private final boolean alpnEnabled;
private final boolean fallbackEnabled;
private final boolean protocolErrorFallbackEnabled;
private final boolean altSvcCacheEnabled;
private final boolean http1OnlyCacheEnabled;
private final boolean h2cCacheEnabled;
private final boolean http2PriorKnowledgeEnabled;
private final boolean h2cUpgradeEnabled;
private final long happyEyeballsDelayMs;
private final long http3BrokenCooldownMs;
private final long http1OnlyCooldownMs;
private final long h2cCacheTtlMs;

private HTTP2ClientProfile(Builder builder) {
id = builder.id;
label = builder.label;
enableHttp3 = builder.enableHttp3;
enableHttp2 = builder.enableHttp2;
enableHttp1 = builder.enableHttp1;
alpnEnabled = builder.alpnEnabled;
fallbackEnabled = builder.fallbackEnabled;
protocolErrorFallbackEnabled = builder.protocolErrorFallbackEnabled;
altSvcCacheEnabled = builder.altSvcCacheEnabled;
http1OnlyCacheEnabled = builder.http1OnlyCacheEnabled;
h2cCacheEnabled = builder.h2cCacheEnabled;
http2PriorKnowledgeEnabled = builder.http2PriorKnowledgeEnabled;
h2cUpgradeEnabled = builder.h2cUpgradeEnabled;
happyEyeballsDelayMs = builder.happyEyeballsDelayMs;
http3BrokenCooldownMs = builder.http3BrokenCooldownMs;
http1OnlyCooldownMs = builder.http1OnlyCooldownMs;
h2cCacheTtlMs = builder.h2cCacheTtlMs;
}

public static Builder builder(String id, String label) {
return new Builder(id, label);
}

public String getId() {
return id;
}

public String getLabel() {
return label;
}

public boolean isEnableHttp3() {
return enableHttp3;
}

public boolean isEnableHttp2() {
return enableHttp2;
}

public boolean isEnableHttp1() {
return enableHttp1;
}

public boolean isAlpnEnabled() {
return alpnEnabled;
}

public boolean isFallbackEnabled() {
return fallbackEnabled;
}

public boolean isProtocolErrorFallbackEnabled() {
return protocolErrorFallbackEnabled;
}

public boolean isAltSvcCacheEnabled() {
return altSvcCacheEnabled;
}

public boolean isHttp1OnlyCacheEnabled() {
return http1OnlyCacheEnabled;
}

public boolean isH2cCacheEnabled() {
return h2cCacheEnabled;
}

public boolean isHttp2PriorKnowledgeEnabled() {
return http2PriorKnowledgeEnabled;
}

public boolean isH2cUpgradeEnabled() {
return h2cUpgradeEnabled;
}

public long getHappyEyeballsDelayMs() {
return happyEyeballsDelayMs;
}

public long getHttp3BrokenCooldownMs() {
return http3BrokenCooldownMs;
}

public long getHttp1OnlyCooldownMs() {
return http1OnlyCooldownMs;
}

public long getH2cCacheTtlMs() {
return h2cCacheTtlMs;
}

public static final class Builder {
private final String id;
private final String label;
private boolean enableHttp3;
private boolean enableHttp2;
private boolean enableHttp1;
private boolean alpnEnabled;
private boolean fallbackEnabled;
private boolean protocolErrorFallbackEnabled;
private boolean altSvcCacheEnabled;
private boolean http1OnlyCacheEnabled;
private boolean h2cCacheEnabled;
private boolean http2PriorKnowledgeEnabled;
private boolean h2cUpgradeEnabled;
private long happyEyeballsDelayMs;
private long http3BrokenCooldownMs;
private long http1OnlyCooldownMs;
private long h2cCacheTtlMs;

private Builder(String id, String label) {
this.id = id;
this.label = label;
}

public Builder enableHttp3(boolean enableHttp3) {
this.enableHttp3 = enableHttp3;
return this;
}

public Builder enableHttp2(boolean enableHttp2) {
this.enableHttp2 = enableHttp2;
return this;
}

public Builder enableHttp1(boolean enableHttp1) {
this.enableHttp1 = enableHttp1;
return this;
}

public Builder alpnEnabled(boolean alpnEnabled) {
this.alpnEnabled = alpnEnabled;
return this;
}

public Builder fallbackEnabled(boolean fallbackEnabled) {
this.fallbackEnabled = fallbackEnabled;
return this;
}

public Builder protocolErrorFallbackEnabled(boolean protocolErrorFallbackEnabled) {
this.protocolErrorFallbackEnabled = protocolErrorFallbackEnabled;
return this;
}

public Builder altSvcCacheEnabled(boolean altSvcCacheEnabled) {
this.altSvcCacheEnabled = altSvcCacheEnabled;
return this;
}

public Builder http1OnlyCacheEnabled(boolean http1OnlyCacheEnabled) {
this.http1OnlyCacheEnabled = http1OnlyCacheEnabled;
return this;
}

public Builder h2cCacheEnabled(boolean h2cCacheEnabled) {
this.h2cCacheEnabled = h2cCacheEnabled;
return this;
}

public Builder http2PriorKnowledgeEnabled(boolean http2PriorKnowledgeEnabled) {
this.http2PriorKnowledgeEnabled = http2PriorKnowledgeEnabled;
return this;
}

public Builder h2cUpgradeEnabled(boolean h2cUpgradeEnabled) {
this.h2cUpgradeEnabled = h2cUpgradeEnabled;
return this;
}

public Builder happyEyeballsDelayMs(long happyEyeballsDelayMs) {
this.happyEyeballsDelayMs = happyEyeballsDelayMs;
return this;
}

public Builder http3BrokenCooldownMs(long http3BrokenCooldownMs) {
this.http3BrokenCooldownMs = http3BrokenCooldownMs;
return this;
}

public Builder http1OnlyCooldownMs(long http1OnlyCooldownMs) {
this.http1OnlyCooldownMs = http1OnlyCooldownMs;
return this;
}

public Builder h2cCacheTtlMs(long h2cCacheTtlMs) {
this.h2cCacheTtlMs = h2cCacheTtlMs;
return this;
}

public HTTP2ClientProfile build() {
return new HTTP2ClientProfile(this);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ public class HTTP2ClientProfileConfig {
private final Boolean http1OnlyCacheEnabled;
private final Boolean h2cCacheEnabled;
private final Boolean http2PriorKnowledgeEnabled;
private final Boolean h2cUpgradeEnabled;
private final Long happyEyeballsDelayMs;
private final Long http3BrokenCooldownMs;
private final Long http1OnlyCooldownMs;
Expand All @@ -30,6 +31,7 @@ private HTTP2ClientProfileConfig(Builder builder) {
this.http1OnlyCacheEnabled = builder.http1OnlyCacheEnabled;
this.h2cCacheEnabled = builder.h2cCacheEnabled;
this.http2PriorKnowledgeEnabled = builder.http2PriorKnowledgeEnabled;
this.h2cUpgradeEnabled = builder.h2cUpgradeEnabled;
this.happyEyeballsDelayMs = builder.happyEyeballsDelayMs;
this.http3BrokenCooldownMs = builder.http3BrokenCooldownMs;
this.http1OnlyCooldownMs = builder.http1OnlyCooldownMs;
Expand Down Expand Up @@ -84,6 +86,10 @@ public Boolean getHttp2PriorKnowledgeEnabled() {
return http2PriorKnowledgeEnabled;
}

public Boolean getH2cUpgradeEnabled() {
return h2cUpgradeEnabled;
}

public Long getHappyEyeballsDelayMs() {
return happyEyeballsDelayMs;
}
Expand Down Expand Up @@ -112,6 +118,7 @@ public static final class Builder {
private Boolean http1OnlyCacheEnabled;
private Boolean h2cCacheEnabled;
private Boolean http2PriorKnowledgeEnabled;
private Boolean h2cUpgradeEnabled;
private Long happyEyeballsDelayMs;
private Long http3BrokenCooldownMs;
private Long http1OnlyCooldownMs;
Expand Down Expand Up @@ -172,6 +179,11 @@ public Builder http2PriorKnowledgeEnabled(Boolean http2PriorKnowledgeEnabled) {
return this;
}

public Builder h2cUpgradeEnabled(Boolean h2cUpgradeEnabled) {
this.h2cUpgradeEnabled = h2cUpgradeEnabled;
return this;
}

public Builder happyEyeballsDelayMs(Long happyEyeballsDelayMs) {
this.happyEyeballsDelayMs = happyEyeballsDelayMs;
return this;
Expand Down
Loading