diff options
author | Simon Brandhof <simon.brandhof@sonarsource.com> | 2017-08-23 17:18:08 +0200 |
---|---|---|
committer | Sébastien Lesaint <sebastien.lesaint@sonarsource.com> | 2017-09-13 15:50:49 +0200 |
commit | 9d5fc95ed97f0dc0e1a797065b5a3870449a9ded (patch) | |
tree | 91126ec5e0985e48887a078ecf757737bca88616 /sonar-ws | |
parent | 5b9d6018431f09d090b71fa3179a9d9bed5dc0ab (diff) | |
download | sonarqube-9d5fc95ed97f0dc0e1a797065b5a3870449a9ded.tar.gz sonarqube-9d5fc95ed97f0dc0e1a797065b5a3870449a9ded.zip |
SONAR-9740 support HTTP headers in API Request and sonar-ws
Diffstat (limited to 'sonar-ws')
7 files changed, 140 insertions, 8 deletions
diff --git a/sonar-ws/src/main/java/org/sonarqube/ws/client/BaseRequest.java b/sonar-ws/src/main/java/org/sonarqube/ws/client/BaseRequest.java index db88b99821a..8b5fbcff005 100644 --- a/sonar-ws/src/main/java/org/sonarqube/ws/client/BaseRequest.java +++ b/sonar-ws/src/main/java/org/sonarqube/ws/client/BaseRequest.java @@ -22,10 +22,12 @@ package org.sonarqube.ws.client; import com.google.common.collect.LinkedListMultimap; import com.google.common.collect.ListMultimap; import java.util.Collection; +import java.util.HashMap; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import java.util.Objects; +import java.util.Optional; import java.util.Set; import java.util.function.Function; import java.util.stream.Collectors; @@ -36,6 +38,7 @@ import org.sonarqube.ws.MediaTypes; import static com.google.common.base.Preconditions.checkArgument; import static com.google.common.base.Strings.isNullOrEmpty; import static java.util.Collections.singletonList; +import static java.util.Collections.unmodifiableSet; import static java.util.Objects.requireNonNull; abstract class BaseRequest<SELF extends BaseRequest> implements WsRequest { @@ -45,6 +48,7 @@ abstract class BaseRequest<SELF extends BaseRequest> implements WsRequest { private String mediaType = MediaTypes.JSON; private final DefaultParameters parameters = new DefaultParameters(); + private final DefaultHeaders headers = new DefaultHeaders(); BaseRequest(String path) { this.path = path; @@ -131,6 +135,17 @@ abstract class BaseRequest<SELF extends BaseRequest> implements WsRequest { return parameters; } + @Override + public Headers getHeaders() { + return headers; + } + + public SELF setHeader(String name, @Nullable String value) { + requireNonNull(name, "Header name can't be null"); + headers.setValue(name, value); + return (SELF) this; + } + private static class DefaultParameters implements Parameters { // preserve insertion order private final ListMultimap<String, String> keyValues = LinkedListMultimap.create(); @@ -168,4 +183,29 @@ abstract class BaseRequest<SELF extends BaseRequest> implements WsRequest { return this; } } + + private static class DefaultHeaders implements Headers { + private final Map<String, String> keyValues = new HashMap<>(); + + @Override + public Optional<String> getValue(String name) { + return Optional.ofNullable(keyValues.get(name)); + } + + private DefaultHeaders setValue(String name, @Nullable String value) { + checkArgument(!isNullOrEmpty(name)); + + if (value == null) { + keyValues.remove(name); + } else { + keyValues.put(name, value); + } + return this; + } + + @Override + public Set<String> getNames() { + return unmodifiableSet(keyValues.keySet()); + } + } } diff --git a/sonar-ws/src/main/java/org/sonarqube/ws/client/Headers.java b/sonar-ws/src/main/java/org/sonarqube/ws/client/Headers.java new file mode 100644 index 00000000000..b289789a1f2 --- /dev/null +++ b/sonar-ws/src/main/java/org/sonarqube/ws/client/Headers.java @@ -0,0 +1,36 @@ +/* + * SonarQube + * Copyright (C) 2009-2017 SonarSource SA + * mailto:info AT sonarsource DOT com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package org.sonarqube.ws.client; + +import java.util.Optional; +import java.util.Set; + +/** + * HTTP headers + * + * @since 6.6 + */ +public interface Headers { + + Optional<String> getValue(String name); + + Set<String> getNames(); + +} diff --git a/sonar-ws/src/main/java/org/sonarqube/ws/client/HttpConnector.java b/sonar-ws/src/main/java/org/sonarqube/ws/client/HttpConnector.java index e652a21e28f..fcc970b7b05 100644 --- a/sonar-ws/src/main/java/org/sonarqube/ws/client/HttpConnector.java +++ b/sonar-ws/src/main/java/org/sonarqube/ws/client/HttpConnector.java @@ -159,11 +159,13 @@ public class HttpConnector implements WsConnector { private Request.Builder prepareOkRequestBuilder(WsRequest getRequest, HttpUrl.Builder urlBuilder) { Request.Builder okHttpRequestBuilder = new Request.Builder() .url(urlBuilder.build()) - .addHeader("Accept", getRequest.getMediaType()) - .addHeader("Accept-Charset", "UTF-8"); + .header("Accept", getRequest.getMediaType()) + .header("Accept-Charset", "UTF-8"); if (credentials != null) { okHttpRequestBuilder.header("Authorization", credentials); } + getRequest.getHeaders().getNames().forEach(name -> + okHttpRequestBuilder.header(name, getRequest.getHeaders().getValue(name).get())); return okHttpRequestBuilder; } @@ -199,6 +201,7 @@ public class HttpConnector implements WsConnector { /** * Private since 5.5. + * * @see HttpConnector#newBuilder() */ private Builder() { diff --git a/sonar-ws/src/main/java/org/sonarqube/ws/client/LocalWsConnector.java b/sonar-ws/src/main/java/org/sonarqube/ws/client/LocalWsConnector.java index 3f2cee3a5c7..5dca504438e 100644 --- a/sonar-ws/src/main/java/org/sonarqube/ws/client/LocalWsConnector.java +++ b/sonar-ws/src/main/java/org/sonarqube/ws/client/LocalWsConnector.java @@ -25,6 +25,7 @@ import java.io.InputStream; import java.io.InputStreamReader; import java.io.Reader; import java.util.List; +import java.util.Optional; import org.sonar.api.server.ws.LocalConnector; import static java.nio.charset.StandardCharsets.UTF_8; @@ -56,11 +57,9 @@ class LocalWsConnector implements WsConnector { private static class DefaultLocalRequest implements LocalConnector.LocalRequest { private final WsRequest wsRequest; - private final Parameters parameters; public DefaultLocalRequest(WsRequest wsRequest) { this.wsRequest = wsRequest; - this.parameters = wsRequest.getParameters(); } @Override @@ -80,17 +79,22 @@ class LocalWsConnector implements WsConnector { @Override public boolean hasParam(String key) { - return !parameters.getValues(key).isEmpty(); + return !wsRequest.getParameters().getValues(key).isEmpty(); } @Override public String getParam(String key) { - return parameters.getValue(key); + return wsRequest.getParameters().getValue(key); } @Override public List<String> getMultiParam(String key) { - return parameters.getValues(key); + return wsRequest.getParameters().getValues(key); + } + + @Override + public Optional<String> getHeader(String name) { + return wsRequest.getHeaders().getValue(name); } } diff --git a/sonar-ws/src/main/java/org/sonarqube/ws/client/WsRequest.java b/sonar-ws/src/main/java/org/sonarqube/ws/client/WsRequest.java index b5ad96a4542..9907ae7b39e 100644 --- a/sonar-ws/src/main/java/org/sonarqube/ws/client/WsRequest.java +++ b/sonar-ws/src/main/java/org/sonarqube/ws/client/WsRequest.java @@ -43,6 +43,8 @@ public interface WsRequest { Parameters getParameters(); + Headers getHeaders(); + enum Method { GET, POST } diff --git a/sonar-ws/src/test/java/org/sonarqube/ws/client/BaseRequestTest.java b/sonar-ws/src/test/java/org/sonarqube/ws/client/BaseRequestTest.java index b473e805eef..c639641a079 100644 --- a/sonar-ws/src/test/java/org/sonarqube/ws/client/BaseRequestTest.java +++ b/sonar-ws/src/test/java/org/sonarqube/ws/client/BaseRequestTest.java @@ -38,7 +38,7 @@ public class BaseRequestTest { @Rule public ExpectedException expectedException = ExpectedException.none(); - FakeRequest underTest = new FakeRequest("api/foo"); + private FakeRequest underTest = new FakeRequest("api/foo"); @Test public void test_defaults() { @@ -96,6 +96,22 @@ public class BaseRequestTest { underTest.setParam(null, "val"); } + @Test + public void headers_are_empty_by_default() { + assertThat(underTest.getHeaders().getNames()).isEmpty(); + } + + @Test + public void set_and_get_headers() { + underTest.setHeader("foo", "fooz"); + underTest.setHeader("bar", "barz"); + + assertThat(underTest.getHeaders().getNames()).containsExactlyInAnyOrder("foo", "bar"); + assertThat(underTest.getHeaders().getValue("foo")).hasValue("fooz"); + assertThat(underTest.getHeaders().getValue("bar")).hasValue("barz"); + assertThat(underTest.getHeaders().getValue("xxx")).isEmpty(); + } + private void assertParameters(MapEntry<String, String>... values) { Parameters parameters = underTest.getParameters(); assertThat(parameters.getKeys()).extracting(key -> MapEntry.entry(key, parameters.getValue(key))).containsExactly(values); diff --git a/sonar-ws/src/test/java/org/sonarqube/ws/client/HttpConnectorTest.java b/sonar-ws/src/test/java/org/sonarqube/ws/client/HttpConnectorTest.java index 449b4fcebe8..c727235a939 100644 --- a/sonar-ws/src/test/java/org/sonarqube/ws/client/HttpConnectorTest.java +++ b/sonar-ws/src/test/java/org/sonarqube/ws/client/HttpConnectorTest.java @@ -96,6 +96,21 @@ public class HttpConnectorTest { } @Test + public void add_headers_to_GET_request() throws Exception { + answerHelloWorld(); + GetRequest request = new GetRequest("api/issues/search") + .setHeader("X-Foo", "fooz") + .setHeader("X-Bar", "barz"); + + underTest = HttpConnector.newBuilder().url(serverUrl).build(); + underTest.call(request); + + RecordedRequest recordedRequest = server.takeRequest(); + assertThat(recordedRequest.getHeader("X-Foo")).isEqualTo("fooz"); + assertThat(recordedRequest.getHeader("X-Bar")).isEqualTo("barz"); + } + + @Test public void use_basic_authentication() throws Exception { answerHelloWorld(); underTest = HttpConnector.newBuilder() @@ -256,6 +271,22 @@ public class HttpConnectorTest { assertThat(recordedRequest.getMethod()).isEqualTo("POST"); assertThat(recordedRequest.getPath()).isEqualTo("/api/issues/search"); assertThat(recordedRequest.getBody().readUtf8()).isEqualTo("severity=MAJOR"); + assertThat(recordedRequest.getHeader("Accept")).isEqualTo("application/x-protobuf"); + } + + @Test + public void add_header_to_POST_request() throws Exception { + answerHelloWorld(); + PostRequest request = new PostRequest("api/issues/search") + .setHeader("X-Foo", "fooz") + .setHeader("X-Bar", "barz"); + + underTest = HttpConnector.newBuilder().url(serverUrl).build(); + underTest.call(request); + + RecordedRequest recordedRequest = server.takeRequest(); + assertThat(recordedRequest.getHeader("X-Foo")).isEqualTo("fooz"); + assertThat(recordedRequest.getHeader("X-Bar")).isEqualTo("barz"); } @Test |