Skip to content

Commit 3b37ec0

Browse files
authored
[JENKINS-76086] Fails to process Bitbucket webhook events with "No processor found" (#1109)
Make the copy of headers a case insensitive on Map
1 parent e4c63c5 commit 3b37ec0

File tree

9 files changed

+57
-18
lines changed

9 files changed

+57
-18
lines changed

src/main/java/com/cloudbees/jenkins/plugins/bitbucket/hooks/BitbucketSCMSourcePushHookReceiver.java

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,6 @@
3939
import java.nio.charset.StandardCharsets;
4040
import java.util.Arrays;
4141
import java.util.Collections;
42-
import java.util.HashMap;
4342
import java.util.List;
4443
import java.util.Map;
4544
import java.util.Map.Entry;
@@ -49,6 +48,7 @@
4948
import org.apache.commons.collections4.EnumerationUtils;
5049
import org.apache.commons.collections4.MultiMapUtils;
5150
import org.apache.commons.collections4.MultiValuedMap;
51+
import org.apache.commons.collections4.map.CaseInsensitiveMap;
5252
import org.apache.commons.collections4.multimap.ArrayListValuedHashMap;
5353
import org.apache.commons.io.IOUtils;
5454
import org.apache.commons.lang3.StringUtils;
@@ -163,7 +163,8 @@ private MultiValuedMap<String, String> getParameters(StaplerRequest2 req) {
163163
}
164164

165165
private Map<String, String> getHeaders(StaplerRequest2 req) {
166-
Map<String, String> reqHeaders = new HashMap<>();
166+
// HTTP headers are case insensitive
167+
Map<String, String> reqHeaders = new CaseInsensitiveMap<>();
167168
for (String headerName : EnumerationUtils.asIterable(req.getHeaderNames())) {
168169
reqHeaders.put(headerName, req.getHeader(headerName));
169170
}

src/test/java/com/cloudbees/jenkins/plugins/bitbucket/hooks/BitbucketSCMSourcePushHookReceiverTest.java

Lines changed: 35 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -31,10 +31,11 @@
3131
import com.cloudbees.jenkins.plugins.bitbucket.test.util.MockRequest;
3232
import java.util.Collections;
3333
import java.util.Enumeration;
34-
import java.util.HashMap;
3534
import java.util.Map;
35+
import java.util.concurrent.atomic.AtomicReference;
3636
import java.util.stream.Stream;
3737
import org.apache.commons.collections4.MultiValuedMap;
38+
import org.apache.commons.collections4.map.CaseInsensitiveMap;
3839
import org.junit.jupiter.api.BeforeAll;
3940
import org.junit.jupiter.api.BeforeEach;
4041
import org.junit.jupiter.api.Test;
@@ -48,6 +49,7 @@
4849

4950
import static org.assertj.core.api.Assertions.assertThat;
5051
import static org.mockito.ArgumentMatchers.any;
52+
import static org.mockito.ArgumentMatchers.anyMap;
5153
import static org.mockito.ArgumentMatchers.anyString;
5254
import static org.mockito.ArgumentMatchers.eq;
5355
import static org.mockito.Mockito.mock;
@@ -58,11 +60,12 @@
5860
@WithJenkins
5961
class BitbucketSCMSourcePushHookReceiverTest {
6062

61-
private static JenkinsRule j;
63+
@SuppressWarnings("unused")
64+
private static JenkinsRule rule;
6265

6366
@BeforeAll
6467
static void init(JenkinsRule rule) {
65-
j = rule;
68+
BitbucketSCMSourcePushHookReceiverTest.rule = rule;
6669
}
6770

6871
private StaplerRequest2 req;
@@ -72,7 +75,7 @@ static void init(JenkinsRule rule) {
7275
@BeforeEach
7376
void setup() throws Exception {
7477
req = mock(StaplerRequest2.class);
75-
headers = new HashMap<>();
78+
headers = new CaseInsensitiveMap<>();
7679
when(req.getHeader(anyString())).thenAnswer(new Answer<String>() {
7780
@Override
7881
public String answer(InvocationOnMock invocation) throws Throwable {
@@ -119,7 +122,9 @@ Stream<BitbucketWebhookProcessor> getHookProcessors() {
119122
when(hookProcessor.getEventType(any(), any())).thenReturn("event:X");
120123

121124
sut.doNotify(req);
125+
@SuppressWarnings("unchecked")
122126
ArgumentCaptor<Map<String, String>> headersCaptor = ArgumentCaptor.forClass(Map.class);
127+
@SuppressWarnings("unchecked")
123128
ArgumentCaptor<MultiValuedMap<String, String>> parametersCaptor = ArgumentCaptor.forClass(MultiValuedMap.class);
124129

125130
verify(hookProcessor).canHandle(headersCaptor.capture(), parametersCaptor.capture());
@@ -176,4 +181,30 @@ Stream<BitbucketWebhookProcessor> getHookProcessors() {
176181
}
177182
}
178183

184+
@Test
185+
void request_headers_must_be_case_insensitive() throws Exception {
186+
AtomicReference<Map<String, String>> requestHeaders = new AtomicReference<>();
187+
188+
BitbucketWebhookProcessor hookProcessor = mock(BitbucketWebhookProcessor.class);
189+
when(hookProcessor.canHandle(anyMap(), any())).thenAnswer(new Answer<Boolean>() {
190+
@Override
191+
public Boolean answer(InvocationOnMock invocation) throws Throwable {
192+
requestHeaders.set(invocation.getArgument(0));
193+
// stop to process the request
194+
return false;
195+
}
196+
});
197+
sut = new BitbucketSCMSourcePushHookReceiver() {
198+
@Override
199+
Stream<BitbucketWebhookProcessor> getHookProcessors() {
200+
return Stream.of(hookProcessor);
201+
}
202+
};
203+
mockRequest();
204+
headers.putAll(HookProcessorTestUtil.getCloudHeaders());
205+
206+
sut.doNotify(req);
207+
assertThat(requestHeaders.get()).containsKeys("X-Request-UUID", "X-Request-UUID".toLowerCase());
208+
}
209+
179210
}

src/test/java/com/cloudbees/jenkins/plugins/bitbucket/hooks/WebhookAutoRegisterListenerTest.java

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -66,8 +66,8 @@ class WebhookAutoRegisterListenerTest {
6666
private static JenkinsRule rule;
6767

6868
@BeforeAll
69-
static void init(JenkinsRule r) {
70-
rule = r;
69+
static void init(JenkinsRule rule) {
70+
WebhookAutoRegisterListenerTest.rule = rule;
7171
}
7272

7373
private WebhookAutoRegisterListener sut;
@@ -108,6 +108,7 @@ void test_register() throws Exception {
108108
});
109109
}
110110

111+
@SuppressWarnings("deprecation")
111112
@Test
112113
void test_do_not_update_plugin_hook_if_no_changes() throws Exception {
113114
String serverURL = "http://localhost:7990/bitbucket";
@@ -127,6 +128,7 @@ void test_do_not_update_plugin_hook_if_no_changes() throws Exception {
127128
.isNotInstanceOf(HttpPut.class);
128129
}
129130

131+
@SuppressWarnings("deprecation")
130132
@Test
131133
void test_update_plugin_hook_when_serverURL_is_changed() throws Exception {
132134
String serverURL = "http://myserver:7990";

src/test/java/com/cloudbees/jenkins/plugins/bitbucket/impl/webhook/cloud/CloudPullRequestWebhookProcessorTest.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@
4343
import jenkins.scm.api.SCMNavigator;
4444
import jenkins.scm.api.SCMSource;
4545
import org.apache.commons.collections4.MultiValuedMap;
46+
import org.apache.commons.collections4.map.CaseInsensitiveMap;
4647
import org.apache.commons.collections4.multimap.ArrayListValuedHashMap;
4748
import org.apache.commons.io.IOUtils;
4849
import org.junit.jupiter.api.BeforeEach;
@@ -70,7 +71,7 @@ public void notifyEvent(SCMHeadEvent<?> event, int delaySeconds) {
7071

7172
@Test
7273
void test_getServerURL_return_always_cloud_URL() throws Exception {
73-
Map<String, String> headers = new HashMap<>();
74+
Map<String, String> headers = new CaseInsensitiveMap<>();
7475
MultiValuedMap<String, String> parameters = new ArrayListValuedHashMap<>();
7576
parameters.put("server_url", "https://localhost:8080");
7677

src/test/java/com/cloudbees/jenkins/plugins/bitbucket/impl/webhook/cloud/CloudPushWebhookProcessorTest.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@
4343
import jenkins.scm.api.SCMHeadEvent;
4444
import jenkins.scm.api.SCMRevision;
4545
import org.apache.commons.collections4.MultiValuedMap;
46+
import org.apache.commons.collections4.map.CaseInsensitiveMap;
4647
import org.apache.commons.collections4.multimap.ArrayListValuedHashMap;
4748
import org.apache.commons.io.IOUtils;
4849
import org.junit.jupiter.api.BeforeEach;
@@ -68,7 +69,7 @@ public void notifyEvent(SCMHeadEvent<?> event, int delaySeconds) {
6869

6970
@Test
7071
void test_getServerURL_return_always_cloud_URL() throws Exception {
71-
Map<String, String> headers = new HashMap<>();
72+
Map<String, String> headers = new CaseInsensitiveMap<>();
7273
MultiValuedMap<String, String> parameters = new ArrayListValuedHashMap<>();
7374
parameters.put("server_url", "https://localhost:8080");
7475

src/test/java/com/cloudbees/jenkins/plugins/bitbucket/impl/webhook/plugin/PluginPullRequestWebhookProcessorTest.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@
4141
import jenkins.scm.api.SCMNavigator;
4242
import jenkins.scm.api.SCMSource;
4343
import org.apache.commons.collections4.MultiValuedMap;
44+
import org.apache.commons.collections4.map.CaseInsensitiveMap;
4445
import org.apache.commons.collections4.multimap.ArrayListValuedHashMap;
4546
import org.apache.commons.io.IOUtils;
4647
import org.junit.jupiter.api.BeforeEach;
@@ -70,7 +71,7 @@ public void notifyEvent(SCMHeadEvent<?> event, int delaySeconds) {
7071

7172
@Test
7273
void test_getServerURL_return_always_cloud_URL() throws Exception {
73-
Map<String, String> headers = new HashMap<>();
74+
Map<String, String> headers = new CaseInsensitiveMap<>();
7475
MultiValuedMap<String, String> parameters = new ArrayListValuedHashMap<>();
7576
parameters.put("server_url", SERVER_URL);
7677

src/test/java/com/cloudbees/jenkins/plugins/bitbucket/impl/webhook/plugin/PluginPushWebhookProcessorTest.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@
4444
import jenkins.scm.api.SCMRevision;
4545
import jenkins.scm.api.SCMSource;
4646
import org.apache.commons.collections4.MultiValuedMap;
47+
import org.apache.commons.collections4.map.CaseInsensitiveMap;
4748
import org.apache.commons.collections4.multimap.ArrayListValuedHashMap;
4849
import org.apache.commons.io.IOUtils;
4950
import org.junit.jupiter.api.BeforeEach;
@@ -74,7 +75,7 @@ public void notifyEvent(SCMHeadEvent<?> event, int delaySeconds) {
7475

7576
@Test
7677
void test_getServerURL_return_always_cloud_URL() throws Exception {
77-
Map<String, String> headers = new HashMap<>();
78+
Map<String, String> headers = new CaseInsensitiveMap<>();
7879
MultiValuedMap<String, String> parameters = new ArrayListValuedHashMap<>();
7980
parameters.put("server_url", SERVER_URL);
8081

src/test/java/com/cloudbees/jenkins/plugins/bitbucket/impl/webhook/server/ServerPushWebhookProcessorTest.java

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -66,11 +66,12 @@ class ServerPushWebhookProcessorTest {
6666
private SCMHeadEvent<?> scmEvent;
6767
private BitbucketEndpoint endpoint;
6868

69+
@SuppressWarnings("unused")
6970
private static JenkinsRule rule;
7071

7172
@BeforeAll
72-
static void init(JenkinsRule r) {
73-
rule = r;
73+
static void init(JenkinsRule rule) {
74+
ServerPushWebhookProcessorTest.rule = rule;
7475
}
7576

7677
@BeforeEach

src/test/java/com/cloudbees/jenkins/plugins/bitbucket/test/util/HookProcessorTestUtil.java

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -23,17 +23,17 @@
2323
*/
2424
package com.cloudbees.jenkins.plugins.bitbucket.test.util;
2525

26-
import java.util.HashMap;
2726
import java.util.Map;
2827
import java.util.UUID;
28+
import org.apache.commons.collections4.map.CaseInsensitiveMap;
2929

3030
public final class HookProcessorTestUtil {
3131

3232
private HookProcessorTestUtil() {
3333
}
3434

3535
public static Map<String, String> getCloudHeaders() {
36-
Map<String, String> headers = new HashMap<>();
36+
Map<String, String> headers = new CaseInsensitiveMap<>();
3737
headers.put("User-Agent", "Bitbucket-Webhooks/2.0");
3838
headers.put("X-Attempt-Number", "1");
3939
headers.put("Content-Type", "application/json");
@@ -45,15 +45,15 @@ public static Map<String, String> getCloudHeaders() {
4545
}
4646

4747
public static Map<String, String> getNativeHeaders() {
48-
Map<String, String> headers = new HashMap<>();
48+
Map<String, String> headers = new CaseInsensitiveMap<>();
4949
headers.put("Content-Type", "application/json; charset=utf-8");
5050
headers.put("X-Request-Id", UUID.randomUUID().toString());
5151
headers.put("User-Agent", "Atlassian HttpClient 4.2.0 / Bitbucket-9.5.2 (9005002) / Default");
5252
return headers;
5353
}
5454

5555
public static Map<String, String> getPluginHeaders() {
56-
Map<String, String> headers = new HashMap<>();
56+
Map<String, String> headers = new CaseInsensitiveMap<>();
5757
headers.put("Content-Type", "application/json; charset=utf-8");
5858
headers.put("X-Bitbucket-Type", "server");
5959
headers.put("User-Agent", "Bitbucket version: 8.18.0, Post webhook plugin version: 7.13.41-SNAPSHOT");

0 commit comments

Comments
 (0)