Skip to content

Commit

Permalink
http headers should be case insensitive
Browse files Browse the repository at this point in the history
  • Loading branch information
heschulz committed Apr 22, 2020
1 parent d84fc70 commit a7e69eb
Show file tree
Hide file tree
Showing 2 changed files with 96 additions and 8 deletions.
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
package org.jenkinsci.plugins.ParameterizedRemoteTrigger;

import java.util.List;
import java.util.Map;
import net.sf.json.JSONObject;

import javax.annotation.CheckForNull;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;

import net.sf.json.JSONObject;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;
import java.util.stream.Collectors;

/**
* Http response containing header, body (JSON format) and response code.
Expand All @@ -16,7 +17,7 @@
public class ConnectionResponse
{
@Nonnull
private final Map<String,List<String>> header;
private final Map<String,List<String>> header = new TreeMap<>(String.CASE_INSENSITIVE_ORDER);

@Nullable @CheckForNull
private final JSONObject body;
Expand All @@ -30,28 +31,35 @@ public class ConnectionResponse

public ConnectionResponse(@Nonnull Map<String, List<String>> header, @Nullable JSONObject body, @Nonnull int responseCode)
{
this.header = header;
loadHeader(header);
this.body = body;
this.rawBody = null;
this.responseCode = responseCode;
}

public ConnectionResponse(@Nonnull Map<String, List<String>> header, @Nullable String rawBody, @Nonnull int responseCode)
{
this.header = header;
loadHeader(header);
this.body = null;
this.rawBody = rawBody;
this.responseCode = responseCode;
}

public ConnectionResponse(@Nonnull Map<String, List<String>> header, @Nonnull int responseCode)
{
this.header = header;
loadHeader(header);
this.body = null;
this.rawBody = null;
this.responseCode = responseCode;
}

private void loadHeader(Map<String, List<String>> header) {
// null key is not compatible with the string Comparator, so we leave it out.
Map<String, List<String>> filtered = header.entrySet().stream().filter(entry -> entry.getKey() != null).collect(
Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
this.header.putAll(filtered);
}

public Map<String,List<String>> getHeader()
{
return header;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
package org.jenkinsci.plugins.ParameterizedRemoteTrigger.remoteJob;

import hudson.AbortException;
import org.eclipse.jetty.server.Response;
import org.jenkinsci.plugins.ParameterizedRemoteTrigger.ConnectionResponse;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
import org.junit.runners.Parameterized.Parameters;

import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;

@RunWith(Parameterized.class)
public class QueueItemTest {

// QueueItem looks for "Location" so test specifically for that
final static private String key = "Location";
final static private String id = "4848912";
final static private String location = String.format("http://example.com/jenkins/my-jenkins1/queue/item/%s/", id);

// invalid header missing Location
final static private Map<String, List<String>> noLocationHeader = new HashMap<String, List<String>>() {{
put("Date", Collections.singletonList("Tue, 21 Apr 2020 02:26:47 GMT"));
put("Server", Collections.singletonList("envoy"));
put(null, Collections.singletonList("HTTP/1.1 201 Created"));
put("Content-Length", Collections.singletonList("0"));
put("X-Envoy-Upstream-Service-Time", Collections.singletonList("15"));
put("X-Content-Type-Options", Collections.singletonList("nosniff"));
}};

// Add the Location to make valid header with typical capitalization
final static private Map<String, List<String>> locationHeader = new HashMap<String, List<String>>(noLocationHeader) {{
put(key, Collections.singletonList(location));
}};

// valid header with all lowercase. Watch out for null key.
final static private Map<String, List<String>> lowerCaseLocationHeader = locationHeader.entrySet().stream().collect(
Collectors.toMap(entry -> entry.getKey() == null ? null : entry.getKey().toLowerCase(),
entry -> entry.getValue()));

@Parameters
public static Collection<Object[]> data() {
return Arrays.asList(new Object[][] {
{ noLocationHeader, false },
{ locationHeader, true },
{ lowerCaseLocationHeader, true }
});
}

@Parameterized.Parameter()
public Map<String, List<String>> header;

@Parameterized.Parameter(1)
public boolean isValid;

@Test
public void test() {
// ConnectionResponse creates case-insensitive map of header
ConnectionResponse connectionResponse = new ConnectionResponse(header, Response.SC_OK);

try {
QueueItem queueItem = new QueueItem(connectionResponse.getHeader());
assertTrue("QueueItem should have thrown exception for invalid header: " + header, isValid);
assertEquals(queueItem.getLocation(), location);
assertEquals(queueItem.getId(), id);
} catch (AbortException e) {
assertFalse("QueueItem thew exception for valid header: " + header, isValid);
}
}
}

0 comments on commit a7e69eb

Please sign in to comment.