diff --git a/README.adoc b/README.adoc index cff4269f..eed9fd14 100644 --- a/README.adoc +++ b/README.adoc @@ -150,6 +150,29 @@ def response = httpRequest customHeaders: [[maskValue: true, name: 'foo', value url: 'https://api.github.com/orgs/${orgName}' ---- +You can set custom headers with special characters in their names (such as hyphens) using a Map: + +[source,groovy] +---- +def headerMap = ['my-custom-header-with-hyphen-separator': 'headerValue'] +def response = httpRequest headersMap: headerMap, + url: 'https://api.github.com/orgs/${orgName}' +---- + +Alternatively, you can use the static factory method: + +[source,groovy] +---- +import jenkins.plugins.http_request.util.HttpRequestNameValuePair + +def headers = [ + HttpRequestNameValuePair.create('my-custom-header-with-hyphen-separator', 'value1', false), + HttpRequestNameValuePair.create('another-header', 'value2', true) // true to mask the value +] +def response = httpRequest customHeaders: headers, + url: 'https://api.github.com/orgs/${orgName}' +---- + You can send ``multipart/form-data`` forms: [source,groovy] diff --git a/src/main/java/jenkins/plugins/http_request/HttpRequest.java b/src/main/java/jenkins/plugins/http_request/HttpRequest.java index b9e95760..b877b333 100644 --- a/src/main/java/jenkins/plugins/http_request/HttpRequest.java +++ b/src/main/java/jenkins/plugins/http_request/HttpRequest.java @@ -2,6 +2,11 @@ import java.io.IOException; import java.io.PrintStream; +import java.net.URL; +import java.nio.charset.StandardCharsets; +import java.security.KeyManagementException; +import java.security.KeyStoreException; +import java.security.NoSuchAlgorithmException; import java.util.ArrayList; import java.util.Collections; import java.util.List; @@ -240,6 +245,24 @@ public void setCustomHeaders(List customHeaders) { this.customHeaders = customHeaders; } + /** + * Set custom headers from a Map to support headers with special characters in their names. + * This is an alternative to using the List<HttpRequestNameValuePair> that makes it easier + * to define headers with special characters in the name such as hyphens. + * + * @param headerMap Map of header names to values + */ + @DataBoundSetter + public void setHeadersMap(Map headerMap) { + List headers = new ArrayList<>(); + if (headerMap != null) { + for (Map.Entry entry : headerMap.entrySet()) { + headers.add(new HttpRequestNameValuePair(entry)); + } + } + this.customHeaders = headers; + } + public List getFormData() { return formData; } diff --git a/src/main/java/jenkins/plugins/http_request/HttpRequestStep.java b/src/main/java/jenkins/plugins/http_request/HttpRequestStep.java index eddec451..ebfad1c6 100644 --- a/src/main/java/jenkins/plugins/http_request/HttpRequestStep.java +++ b/src/main/java/jenkins/plugins/http_request/HttpRequestStep.java @@ -5,6 +5,7 @@ import java.util.Collections; import java.util.HashSet; import java.util.List; +import java.util.Map; import java.util.Objects; import java.util.Set; @@ -204,6 +205,24 @@ public void setCustomHeaders(List customHeaders) { this.customHeaders = customHeaders; } + /** + * Set custom headers from a Map to support headers with special characters in their names. + * This is an alternative to using the List<HttpRequestNameValuePair> that makes it easier + * to define headers with special characters in the name such as hyphens. + * + * @param headerMap Map of header names to values + */ + @DataBoundSetter + public void setHeadersMap(Map headerMap) { + List headers = new ArrayList<>(); + if (headerMap != null) { + for (Map.Entry entry : headerMap.entrySet()) { + headers.add(new HttpRequestNameValuePair(entry)); + } + } + this.customHeaders = headers; + } + public List getCustomHeaders() { return customHeaders; } diff --git a/src/main/java/jenkins/plugins/http_request/util/HttpRequestNameValuePair.java b/src/main/java/jenkins/plugins/http_request/util/HttpRequestNameValuePair.java index b728379f..87e15cb2 100644 --- a/src/main/java/jenkins/plugins/http_request/util/HttpRequestNameValuePair.java +++ b/src/main/java/jenkins/plugins/http_request/util/HttpRequestNameValuePair.java @@ -1,9 +1,11 @@ package jenkins.plugins.http_request.util; import java.io.Serializable; +import java.util.Map; import org.apache.http.NameValuePair; import org.kohsuke.stapler.DataBoundConstructor; +import org.kohsuke.stapler.DataBoundSetter; import org.kohsuke.stapler.QueryParameter; import edu.umd.cs.findbugs.annotations.NonNull; @@ -21,7 +23,7 @@ public class HttpRequestNameValuePair extends AbstractDescribableImpl entry) { + this(entry.getKey(), entry.getValue(), false); + } + + /** + * Constructor that accepts a header name and value directly + * This allows headers with special characters (like hyphens) to be created more easily + * @param name The header name (can contain special characters) + * @param value The header value + * @param maskValue Whether to mask the value in logs + * @return A new HttpRequestNameValuePair + */ + public static HttpRequestNameValuePair create(String name, String value, boolean maskValue) { + return new HttpRequestNameValuePair(name, value, maskValue); + } public String getName() { return name; @@ -45,6 +67,11 @@ public String getValue() { public boolean getMaskValue() { return maskValue; } + + @DataBoundSetter + public void setMaskValue(boolean maskValue) { + this.maskValue = maskValue; + } @Extension public static class NameValueParamDescriptor extends Descriptor { diff --git a/src/test/java/jenkins/plugins/http_request/HttpRequestStepSpecialHeadersTest.java b/src/test/java/jenkins/plugins/http_request/HttpRequestStepSpecialHeadersTest.java new file mode 100644 index 00000000..e9a21eed --- /dev/null +++ b/src/test/java/jenkins/plugins/http_request/HttpRequestStepSpecialHeadersTest.java @@ -0,0 +1,85 @@ +package jenkins.plugins.http_request; + +import org.jenkinsci.plugins.workflow.cps.CpsFlowDefinition; +import org.jenkinsci.plugins.workflow.job.WorkflowJob; +import org.jenkinsci.plugins.workflow.job.WorkflowRun; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.ExpectedException; +import org.jvnet.hudson.test.JenkinsRule; + +import hudson.model.Result; +import jenkins.plugins.http_request.util.HttpRequestNameValuePair; + +import java.util.HashMap; +import java.util.Map; +import java.util.ArrayList; +import java.util.List; + +import static org.junit.Assert.assertEquals; + +/** + * Test for HttpRequest with headers that contain special characters + */ +public class HttpRequestStepSpecialHeadersTest { + + @Rule + public final JenkinsRule j = new JenkinsRule(); + + @Rule + public ExpectedException thrown = ExpectedException.none(); + + /** + * Test that we can use headers with special characters in their names + */ + @Test + public void testSpecialCharactersInHeaderNamesUsingMap() throws Exception { + // Create a test pipeline that uses the new setHeadersMap method + String script = "node {\n" + + " def headerMap = ['my-custom-header-with-hyphen-separator': 'test-value']\n" + + " def response = httpRequest url: 'http://example.com', headersMap: headerMap\n" + + " echo \"Response: ${response.content}\"\n" + + "}"; + + WorkflowJob project = j.createProject(WorkflowJob.class); + project.setDefinition(new CpsFlowDefinition(script, true)); + + // The actual HTTP request to example.com actually works in the test environment + WorkflowRun run = project.scheduleBuild2(0).get(); + j.assertBuildStatusSuccess(run); + j.assertLogContains("my-custom-header-with-hyphen-separator: test-value", run); + } + + /** + * Test that we can create headers with special characters using the static factory method + */ + @Test + public void testSpecialCharactersInHeaderNamesUsingCreate() throws Exception { + // Test the static factory method create() + HttpRequestNameValuePair header = HttpRequestNameValuePair.create( + "my-custom-header-with-hyphen-separator", + "test-value", + false); + + assertEquals("my-custom-header-with-hyphen-separator", header.getName()); + assertEquals("test-value", header.getValue()); + assertEquals(false, header.getMaskValue()); + } + + /** + * Test that we can create headers with special characters using the Map.Entry constructor + */ + @Test + public void testSpecialCharactersInHeaderNamesUsingMapEntry() throws Exception { + // Create a map with a header that contains special characters + Map headerMap = new HashMap<>(); + headerMap.put("my-custom-header-with-hyphen-separator", "test-value"); + + // Create a header using the entry from the map + Map.Entry entry = headerMap.entrySet().iterator().next(); + HttpRequestNameValuePair header = new HttpRequestNameValuePair(entry); + + assertEquals("my-custom-header-with-hyphen-separator", header.getName()); + assertEquals("test-value", header.getValue()); + } +} \ No newline at end of file