From 85180bc80e0bb02ae6b7963088b00380c1ef7e99 Mon Sep 17 00:00:00 2001 From: iroqueta Date: Wed, 29 Apr 2026 17:51:14 -0300 Subject: [PATCH] HttpClient: send AddVariable params as query string on GETs and read them on the server Two related fixes for AddVariable usage on GET requests. Client side (HttpClientJavaLib + GXHttpClient): On GET, variables added with AddVariable were serialized as a multipart body. Servers, proxies and CDNs ignore the body of a GET so the values never reached the destination. They now go to the URL query string, URL-encoded in UTF-8. POST/PUT/DELETE keep using the body as before. Server side (HttpContextWeb): HttpRequest.GetVariable() consulted only the request body. On a GET this body is empty so values sent via the query string were invisible. Now, only on GET, if the body parsed empty we fall back to the query string. POST and any other verb are unchanged: the body still has precedence and the query string is not consulted. --- .../com/genexus/internet/GXHttpClient.java | 49 +++++++++++++++---- .../genexus/internet/HttpClientJavaLib.java | 14 ++++-- .../com/genexus/webpanels/HttpContextWeb.java | 10 +++- 3 files changed, 60 insertions(+), 13 deletions(-) diff --git a/common/src/main/java/com/genexus/internet/GXHttpClient.java b/common/src/main/java/com/genexus/internet/GXHttpClient.java index 607ccf071..e699ed94d 100644 --- a/common/src/main/java/com/genexus/internet/GXHttpClient.java +++ b/common/src/main/java/com/genexus/internet/GXHttpClient.java @@ -15,6 +15,7 @@ import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.parsers.ParserConfigurationException; import java.io.*; +import java.net.URLEncoder; import java.util.Hashtable; import java.util.Vector; @@ -571,21 +572,51 @@ protected String setPathUrl(String url) { } boolean firstMultiPart; - @SuppressWarnings("unchecked") + protected byte[] getData() + { + return getData(true); + } + + protected String getQueryStringFromVariables() + { + if (getVariablesToSend() == null || getVariablesToSend().isEmpty()) + return ""; + StringBuilder sb = new StringBuilder(); + boolean first = true; + for (Object key : getVariablesToSend().keySet()) + { + if (!first) sb.append('&'); + try + { + sb.append(URLEncoder.encode((String) key, "UTF-8")) + .append('=') + .append(URLEncoder.encode((String) getVariablesToSend().get(key), "UTF-8")); + } + catch (UnsupportedEncodingException ignored) { /* UTF-8 always supported */ } + first = false; + } + return sb.toString(); + } + + @SuppressWarnings("unchecked") + protected byte[] getData(boolean includeVariablesAsMultipart) { byte[] out = new byte[0]; firstMultiPart = false; - int variablesCount = getVariablesToSend().size(); - int count = 1; - for (Object key: getVariablesToSend().keySet()) + if (includeVariablesAsMultipart) { - if (count == variablesCount) - firstMultiPart = true; - String value = getMultipartTemplate().getFormDataTemplate((String)key, (String)getVariablesToSend().get(key)); - getContentToSend().add(0, value); //Variables al principio - count++; + int variablesCount = getVariablesToSend().size(); + int count = 1; + for (Object key: getVariablesToSend().keySet()) + { + if (count == variablesCount) + firstMultiPart = true; + String value = getMultipartTemplate().getFormDataTemplate((String)key, (String)getVariablesToSend().get(key)); + getContentToSend().add(0, value); //Variables al principio + count++; + } } for (int idx = 0; idx < getContentToSend().size(); idx++) diff --git a/java/src/main/java/com/genexus/internet/HttpClientJavaLib.java b/java/src/main/java/com/genexus/internet/HttpClientJavaLib.java index 2573a2b6a..8e325e299 100644 --- a/java/src/main/java/com/genexus/internet/HttpClientJavaLib.java +++ b/java/src/main/java/com/genexus/internet/HttpClientJavaLib.java @@ -547,9 +547,17 @@ public void execute(String method, String url) { try (CloseableHttpClient httpClient = this.httpClientBuilder.build()) { if (method.equalsIgnoreCase("GET")) { - byte[] data = getData(); + // Variables added via addVariable are appended to the query string, + // not serialized as a multipart body (which servers ignore on GETs). + String queryFromVars = getQueryStringFromVariables(); + String finalUrl = url; + if (!queryFromVars.isEmpty()) { + finalUrl = url + (url.contains("?") ? "&" : "?") + queryFromVars; + } + + byte[] data = getData(false); // body only from addBytes/addString, no variables if (data.length > 0) { - HttpGetWithBody httpGetWithBody = new HttpGetWithBody(url.trim()); + HttpGetWithBody httpGetWithBody = new HttpGetWithBody(finalUrl.trim()); httpGetWithBody.setConfig(reqConfig); Set keys = getheadersToSend().keySet(); for (String header : keys) { @@ -559,7 +567,7 @@ public void execute(String method, String url) { response = httpClient.execute(httpGetWithBody, httpClientContext); } else { - HttpGet httpget = new HttpGet(url.trim()); + HttpGet httpget = new HttpGet(finalUrl.trim()); httpget.setConfig(reqConfig); Set keys = getheadersToSend().keySet(); for (String header : keys) { diff --git a/java/src/main/java/com/genexus/webpanels/HttpContextWeb.java b/java/src/main/java/com/genexus/webpanels/HttpContextWeb.java index 23fef2fe5..e008cede5 100644 --- a/java/src/main/java/com/genexus/webpanels/HttpContextWeb.java +++ b/java/src/main/java/com/genexus/webpanels/HttpContextWeb.java @@ -1242,7 +1242,15 @@ static private Hashtable parseMultipartPostData(FileItemCollec static public Hashtable parsePostData(IHttpServletRequest request, IServletInputStream in) { try { // Nuestra versión del parsePostData utiliza UTF-8 - return com.genexus.webpanels.HttpUtils.parsePostData(in); + Hashtable postData = com.genexus.webpanels.HttpUtils.parsePostData(in); + // On GET requests, if the body yielded no variables, fall back to the query string. + // POST/PUT/DELETE/... behavior is unchanged: only the body is read. + if ((postData == null || postData.isEmpty()) + && request != null + && "GET".equalsIgnoreCase(request.getMethod())) { + return com.genexus.webpanels.HttpUtils.parsePostData(request); + } + return postData; } catch (IllegalArgumentException e) { return com.genexus.webpanels.HttpUtils.parsePostData(request); }