Skip to content

Commit 63d3d18

Browse files
yunfan24Aias00
andauthored
[bugfix] Fix http header being incorrectly encoded. (apache#3108)
Co-authored-by: aias00 <[email protected]>
1 parent cec8d8b commit 63d3d18

File tree

4 files changed

+88
-10
lines changed

4 files changed

+88
-10
lines changed

e2e/data/monitor-http.json

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,11 @@
7373
"field": "successCode",
7474
"type": 4,
7575
"paramValue": "200, 201"
76+
},
77+
{
78+
"field": "enableUrlEncoding",
79+
"type": 1,
80+
"paramValue": true
7681
}
7782
]
7883
}

hertzbeat-collector/hertzbeat-collector-basic/src/main/java/org/apache/hertzbeat/collector/collect/http/HttpCollectImpl.java

Lines changed: 59 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,7 @@
8686
import org.springframework.http.MediaType;
8787
import org.springframework.util.CollectionUtils;
8888
import org.springframework.util.StringUtils;
89+
import org.springframework.web.util.UriUtils;
8990
import org.xml.sax.InputSource;
9091
import org.w3c.dom.Document;
9192
import org.w3c.dom.Node;
@@ -509,13 +510,37 @@ public HttpUriRequest createHttpRequest(HttpProtocol httpProtocol) {
509510
}
510511
// params
511512
Map<String, String> params = httpProtocol.getParams();
513+
boolean enableUrlEncoding = Boolean.parseBoolean(httpProtocol.getEnableUrlEncoding());
514+
StringBuilder queryParams = new StringBuilder();
515+
512516
if (params != null && !params.isEmpty()) {
513517
for (Map.Entry<String, String> param : params.entrySet()) {
514-
if (StringUtils.hasText(param.getValue())) {
515-
requestBuilder.addParameter(param.getKey(), TimeExpressionUtil.calculate(param.getValue()));
518+
String key = param.getKey();
519+
String value = param.getValue();
520+
521+
if (!StringUtils.hasText(key)) {
522+
continue;
523+
}
524+
525+
if (queryParams.length() > 0) {
526+
queryParams.append("&");
527+
}
528+
529+
if (enableUrlEncoding) {
530+
key = UriUtils.encodeQueryParam(key, "UTF-8");
531+
}
532+
queryParams.append(key);
533+
534+
if (StringUtils.hasText(value)) {
535+
String calculatedValue = TimeExpressionUtil.calculate(value);
536+
if (enableUrlEncoding) {
537+
calculatedValue = UriUtils.encodeQueryParam(calculatedValue, "UTF-8");
538+
}
539+
queryParams.append("=").append(calculatedValue);
516540
}
517541
}
518542
}
543+
519544
// The default request header can be overridden if customized
520545
// keep-alive
521546
requestBuilder.addHeader(HttpHeaders.CONNECTION, NetworkConstants.KEEP_ALIVE);
@@ -525,8 +550,7 @@ public HttpUriRequest createHttpRequest(HttpProtocol httpProtocol) {
525550
if (headers != null && !headers.isEmpty()) {
526551
for (Map.Entry<String, String> header : headers.entrySet()) {
527552
if (StringUtils.hasText(header.getValue())) {
528-
requestBuilder.addHeader(CollectUtil.replaceUriSpecialChar(header.getKey()),
529-
CollectUtil.replaceUriSpecialChar(header.getValue()));
553+
requestBuilder.addHeader(header.getKey(), header.getValue());
530554
}
531555
}
532556
}
@@ -560,23 +584,48 @@ public HttpUriRequest createHttpRequest(HttpProtocol httpProtocol) {
560584
requestBuilder.setEntity(new StringEntity(httpProtocol.getPayload(), StandardCharsets.UTF_8));
561585
}
562586

563-
// uri
564-
String uri = CollectUtil.replaceUriSpecialChar(httpProtocol.getUrl());
565-
if (IpDomainUtil.isHasSchema(httpProtocol.getHost())) {
587+
// uri encode
588+
String uri;
589+
if (enableUrlEncoding) {
590+
// if the url contains parameters directly
591+
if (httpProtocol.getUrl().contains("?")) {
592+
String path = httpProtocol.getUrl().substring(0, httpProtocol.getUrl().indexOf("?"));
593+
String query = httpProtocol.getUrl().substring(httpProtocol.getUrl().indexOf("?") + 1);
594+
uri = UriUtils.encodePath(path, "UTF-8") + "?" + UriUtils.encodeQuery(query, "UTF-8");
595+
} else {
596+
uri = UriUtils.encodePath(httpProtocol.getUrl(), "UTF-8");
597+
}
598+
} else {
599+
uri = httpProtocol.getUrl();
600+
}
566601

567-
requestBuilder.setUri(httpProtocol.getHost() + ":" + httpProtocol.getPort() + uri);
602+
// append query params
603+
if (queryParams.length() > 0) {
604+
uri += (uri.contains("?") ? "&" : "?") + queryParams.toString();
605+
}
606+
607+
String finalUri;
608+
if (IpDomainUtil.isHasSchema(httpProtocol.getHost())) {
609+
finalUri = httpProtocol.getHost() + ":" + httpProtocol.getPort() + uri;
568610
} else {
569611
String ipAddressType = IpDomainUtil.checkIpAddressType(httpProtocol.getHost());
570612
String baseUri = NetworkConstants.IPV6.equals(ipAddressType)
571613
? String.format("[%s]:%s%s", httpProtocol.getHost(), httpProtocol.getPort(), uri)
572614
: String.format("%s:%s%s", httpProtocol.getHost(), httpProtocol.getPort(), uri);
573615
boolean ssl = Boolean.parseBoolean(httpProtocol.getSsl());
574616
if (ssl) {
575-
requestBuilder.setUri(NetworkConstants.HTTPS_HEADER + baseUri);
617+
finalUri = NetworkConstants.HTTPS_HEADER + baseUri;
576618
} else {
577-
requestBuilder.setUri(NetworkConstants.HTTP_HEADER + baseUri);
619+
finalUri = NetworkConstants.HTTP_HEADER + baseUri;
578620
}
579621
}
622+
623+
try {
624+
requestBuilder.setUri(finalUri);
625+
} catch (IllegalArgumentException e) {
626+
log.warn("Invalid URI with illegal characters: {}. User has disabled URL encoding, not applying any encoding.", finalUri);
627+
throw e;
628+
}
580629

581630
// custom timeout
582631
int timeout = CollectUtil.getTimeout(httpProtocol.getTimeout(), 0);

hertzbeat-common/src/main/java/org/apache/hertzbeat/common/entity/job/protocol/HttpProtocol.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,12 @@ public class HttpProtocol implements CommonRequestProtocol, Protocol {
9595
*/
9696
private List<String> successCodes;
9797

98+
/**
99+
* Whether to enable URL encoding for the path. Default is true.
100+
* When true, the URL path will be encoded. When false, the URL path will not be encoded.
101+
*/
102+
private String enableUrlEncoding = "true";
103+
98104
/**
99105
* authentication information
100106
*/

hertzbeat-manager/src/main/resources/define/app-api.yml

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -246,6 +246,20 @@ params:
246246
defaultValue: '200, 201'
247247
# hide param-true or false
248248
hide: true
249+
# field-param field key
250+
- field: enableUrlEncoding
251+
# name-param field display i18n name
252+
name:
253+
zh-CN: 启用URL编码(UTF-8)
254+
en-US: Enable URL Encoding(UTF-8)
255+
# type-param field type(most mapping the html input type)
256+
type: boolean
257+
# required-true or false
258+
required: true
259+
# default value
260+
defaultValue: true
261+
# hide param-true or false
262+
hide: true
249263
# collect metrics config list
250264
metrics:
251265
# metrics - summary
@@ -286,6 +300,8 @@ metrics:
286300
method: ^_^httpMethod^_^
287301
# if enabled https
288302
ssl: ^_^ssl^_^
303+
# enable url encoding
304+
enableUrlEncoding: ^_^enableUrlEncoding^_^
289305
# http request payload
290306
payload: ^_^payload^_^
291307
# http request header content
@@ -344,6 +360,8 @@ metrics:
344360
method: GET
345361
# if enabled https
346362
ssl: ^_^ssl^_^
363+
# enable url encoding
364+
enableUrlEncoding: ^_^enableUrlEncoding^_^
347365
authorization:
348366
# http auth type: Basic Auth, Digest Auth, Bearer Token
349367
type: ^_^authType^_^

0 commit comments

Comments
 (0)