Skip to content

Commit

Permalink
Merge remote-tracking branch 'upstream/master' into fix-cert-auth
Browse files Browse the repository at this point in the history
  • Loading branch information
jimklimov committed Jun 26, 2023
2 parents c3d5be2 + ead1ee1 commit 2937c95
Show file tree
Hide file tree
Showing 10 changed files with 96 additions and 54 deletions.
2 changes: 1 addition & 1 deletion .mvn/extensions.xml
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,6 @@
<extension>
<groupId>io.jenkins.tools.incrementals</groupId>
<artifactId>git-changelist-maven-extension</artifactId>
<version>1.4</version>
<version>1.6</version>
</extension>
</extensions>
70 changes: 54 additions & 16 deletions README.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -30,19 +30,38 @@ If there is no such setting then it will use the default from global settings. D

== Features

The following features are available in both Pipeline and traditional project types:

* Programmable HTTP method: GET, POST, PUT, PATCH, DELETE, or HEAD
* Programmable range of expected response codes (a response code outside the range fails the build)
* Supports Basic Authentication (see global configuration)
* Supports Form Authentication (see global configuration)
* Supports Certificate-based Authentication with a Jenkins stored credential
* You can specify a string that must be present in the response (if the string is not present, the
build fails)
* You can set a connection timeout limit (build fails if timeout is exceeded)
* You can set an "Accept" header directly
* You can set a "Content-Type" header directly
* You can set any custom header
The following powerful features are available in both Pipeline and traditional project types, giving you greater control and flexibility over your builds:


* Programmable HTTP method:
Choose from a variety of HTTP methods, including GET, POST, MKCOL, PUT, PATCH, DELETE, OPTIONS, or HEAD, to suit your project's specific needs.

* Programmable range of expected response codes:
Specify a range of expected response codes for your build, and if the response code falls outside the specified range, the build will fail, saving you time and hassle.

* Supports Basic Authentication:
Use Basic Authentication to ensure that only authorized users can access your project's resources, providing an additional layer of security.

* Supports Form Authentication:
Form Authentication enables users to authenticate themselves by submitting a username and password through a form, ensuring that only authorized users can access your resources.

* Supports Certificate-based Authentication:
Use a certificate from a Jenkins stored credential to authenticate your HTTPS requests to a remote server.

* Specify a required string in the response:
Ensure that a specific string is present in the response by specifying it beforehand. If the string is not present, the build will fail, alerting you to the issue.

* Set a connection timeout limit:
Prevent builds from taking too long by setting a connection timeout limit. If the limit is exceeded, the build will fail, saving you time and resources.

* Set an "Accept" header directly:
Set the "Accept" header directly, providing greater control over the type of data that the server returns in response to a request.

* Set a "Content-Type" header directly:
Set the "Content-Type" header directly, specifying the type of data that you are sending in your request, helping to ensure that the server can correctly process your request.

* Set any custom header:
Set any custom header that you require, enabling you to interact with APIs or web services that require specific headers or authentication protocols.

=== Basic plugin features

Expand Down Expand Up @@ -77,13 +96,14 @@ node() {
}
----

You can access the response status code and content programmatically:
You can access the response status code, content and headers programmatically:

[source,groovy]
----
def response = httpRequest "http://httpbin.org/response-headers?param1=${param1}"
println('Status: '+response.status)
println('Response: '+response.content)
println("Status: ${response.status}")
println("Response: ${response.content}")
println("Headers: ${response.headers}")
----

You may also send content in the body of the request, such as for a PATCH request:
Expand Down Expand Up @@ -270,6 +290,24 @@ def response = httpRequest authentication: 'user_with_cert_and_ca',
url: 'https://sut123.local.domain:8443/api/v1/status/debug'
----

A basic WebDAV upload can be built using ``MKCOL`` and ``PUT`` like so:

[source,groovy]
----
// create directory aka a collection
httpRequest authenticate: 'my-jenkins-credential-id',
httpMode: 'MKCOL',
// on Apache httpd 201 = collection created, 405 = collection already exists
validResponseCodes: '201,405',
url: "https://example.com/webdav-enabled-server/reports/${version}/"
// upload a file
httpRequest authenticate: 'my-jenkins-credential-id',
httpMode: 'PUT',
validResponseCodes: '201',
url: "https://example.com/reports/${version}/your-report-maybe.html",
uploadFile: './local/path/to/report.html'
----

For details on the Pipeline features, use the Pipeline snippet generator in the Pipeline job
configuration.

Expand Down
6 changes: 3 additions & 3 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ THE SOFTWARE.
<parent>
<groupId>org.jenkins-ci.plugins</groupId>
<artifactId>plugin</artifactId>
<version>4.53</version>
<version>4.66</version>
<relativePath />
</parent>

Expand All @@ -48,7 +48,7 @@ THE SOFTWARE.
</licenses>

<properties>
<revision>1.17</revision>
<revision>1.18</revision>
<changelist>-SNAPSHOT</changelist>
<gitHubRepo>jenkinsci/http-request-plugin</gitHubRepo>
<jenkins.version>2.361.4</jenkins.version>
Expand Down Expand Up @@ -76,7 +76,7 @@ THE SOFTWARE.
<dependency>
<groupId>io.jenkins.tools.bom</groupId>
<artifactId>bom-2.361.x</artifactId>
<version>1763.v092b_8980a_f5e</version>
<version>2102.v854b_fec19c92</version>
<scope>import</scope>
<type>pom</type>
</dependency>
Expand Down
3 changes: 2 additions & 1 deletion src/main/java/jenkins/plugins/http_request/HttpMode.java
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,8 @@ public enum HttpMode {
PUT,
DELETE,
OPTIONS,
PATCH;
PATCH,
MKCOL;

public static ListBoxModel getFillItems() {
ListBoxModel items = new ListBoxModel();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PrintStream;
import java.io.UnsupportedEncodingException;
import java.net.ConnectException;
import java.net.Socket;
import java.net.SocketTimeoutException;
Expand Down Expand Up @@ -291,11 +290,7 @@ public ResponseContentSupplier call() throws RuntimeException {

private PrintStream logger() {
if (localLogger == null) {
try {
localLogger = new PrintStream(remoteLogger, true, StandardCharsets.UTF_8.name());
} catch (UnsupportedEncodingException e) {
throw new IllegalStateException(e);
}
localLogger = new PrintStream(remoteLogger, true, StandardCharsets.UTF_8);
}
return localLogger;
}
Expand Down Expand Up @@ -472,7 +467,7 @@ private void responseCodeIsValid(ResponseContentSupplier response) throws AbortE
return;
}
}
throw new AbortException("Fail: Status code " + response.getStatus() + " is not in the accepted range: " + validResponseCodes);
throw new AbortException("Fail: Status code " + response.getStatus() + " is not in the accepted range: " + validResponseCodes + " while calling " + url);
}

private void processResponse(ResponseContentSupplier response) throws IOException, InterruptedException {
Expand All @@ -487,7 +482,7 @@ private void processResponse(ResponseContentSupplier response) throws IOExceptio
//validate content
if (!validResponseContent.isEmpty()) {
if (!response.getContent().contains(validResponseContent)) {
throw new AbortException("Fail: Response doesn't contain expected content '" + validResponseContent + "'");
throw new AbortException("Fail: Response doesn't contain expected content '" + validResponseContent + "'" + " while calling " + url);
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,8 @@ private HttpRequestBase doCreateRequestBase(RequestAction requestAction) throws
http = new HttpPatch(uri);
} else if (requestAction.getMode() == HttpMode.OPTIONS) {
return new HttpOptions(getUrlWithParams(requestAction));
} else if (requestAction.getMode() == HttpMode.MKCOL) {
return new HttpMkcol(uri);
} else { //default post
http = new HttpPost(uri);
}
Expand Down
19 changes: 19 additions & 0 deletions src/main/java/jenkins/plugins/http_request/util/HttpMkcol.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package jenkins.plugins.http_request.util;

import java.net.URI;

import org.apache.http.client.methods.HttpEntityEnclosingRequestBase;

public class HttpMkcol extends HttpEntityEnclosingRequestBase {
public final static String METHOD_NAME = "MKCOL";

public HttpMkcol(final String uri) {
super();
setURI(URI.create(uri));
}

@Override
public String getMethod() {
return METHOD_NAME;
}
}
Original file line number Diff line number Diff line change
@@ -1,33 +1,16 @@
<?jelly escape-by-default='true'?>
<j:jelly xmlns:j="jelly:core" xmlns:f="/lib/form" xmlns:d="jelly:define" xmlns:local="local">
<d:taglib uri="local">
<!-- TODO remove and use div instead after baseline is 2.264 or newer -->
<d:tag name="blockWrapper">
<j:choose>
<j:when test="${divBasedFormLayout}">
<div>
<d:invokeBody/>
</div>
</j:when>
<j:otherwise>
<table style="width:100%">
<d:invokeBody/>
</table>
</j:otherwise>
</j:choose>
</d:tag>
</d:taglib>
<j:jelly xmlns:j="jelly:core" xmlns:f="/lib/form" xmlns:d="jelly:define">
<f:section title="HTTP Request">
<f:entry title="Form Authentication">
<f:repeatable field="formAuthentications">
<local:blockWrapper>
<div>
<f:entry title="Key Name" field="keyName" help="/plugin/http_request/help-keyName.html">
<f:textbox name="formAuthentication.keyName" />
</f:entry>

<f:entry title="Actions">
<f:repeatable field="actions" help="/plugin/http_request/help-authentication-actions.html">
<local:blockWrapper>
<div>
<f:entry title="URL" field="url" help="/plugin/http_request/help-url.html">
<f:textbox name="actionFormAuthentication.url" />
</f:entry>
Expand All @@ -36,7 +19,7 @@
</f:entry>
<f:entry title="Parameters" help="/plugin/http_request/help-authentication-parameters.html">
<f:repeatable field="params">
<local:blockWrapper width="100%">
<div width="100%">
<f:entry title="Name" field="name" help="/plugin/http_request/help-authentication-parameter-name.html">
<f:textbox name="httpRequestNameValuePair.name" />
</f:entry>
Expand All @@ -48,15 +31,15 @@
<f:repeatableDeleteButton />
</div>
</f:entry>
</local:blockWrapper>
</div>
</f:repeatable>
</f:entry>
<f:entry>
<div align="right">
<f:repeatableDeleteButton />
</div>
</f:entry>
</local:blockWrapper>
</div>
</f:repeatable>
</f:entry>

Expand All @@ -65,7 +48,7 @@
<f:repeatableDeleteButton />
</div>
</f:entry>
</local:blockWrapper>
</div>
</f:repeatable>
</f:entry>
</f:section>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@
import org.jenkinsci.plugins.workflow.job.WorkflowJob;
import org.jenkinsci.plugins.workflow.job.WorkflowRun;

import com.gargoylesoftware.htmlunit.html.HtmlPage;
import org.htmlunit.html.HtmlPage;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,7 @@ public void badContentFailsTheBuild() throws Exception {
// Check expectations
j.assertBuildStatus(Result.FAILURE, run);
j.assertLogContains("Fail: Response doesn't contain expected content 'bad content'", run);
j.assertLogContains(" while calling " + baseURL(), run);
j.assertLogContains("Success: Status code 200 is in the accepted range: 100:399", run);
}

Expand Down Expand Up @@ -248,6 +249,7 @@ public void invalidResponseCodeFailsTheBuild() throws Exception {
j.assertBuildStatus(Result.FAILURE, run);
j.assertLogContains("Throwing status 400 for test",run);
j.assertLogContains("Fail: Status code 400 is not in the accepted range: 100:399", run);
j.assertLogContains(" while calling " + baseURL(), run);
}

@Test
Expand All @@ -272,6 +274,7 @@ public void invalidResponseCodeIsAccepted() throws Exception {
j.assertBuildStatusSuccess(run);
j.assertLogContains("Throwing status 400 for test",run);
j.assertLogContains("Success: Status code 400 is in the accepted range: 100:599", run);
j.assertLogNotContains(" while calling " + baseURL(), run);
}

@Test
Expand Down Expand Up @@ -448,6 +451,7 @@ public void timeoutFailsTheBuild() throws Exception {
// Check expectations
j.assertBuildStatus(Result.FAILURE, run);
j.assertLogContains("Fail: Status code 408 is not in the accepted range: 100:399", run);
j.assertLogContains(" while calling " + baseURL(), run);
}

@Test
Expand Down

0 comments on commit 2937c95

Please sign in to comment.