WIP some HTTP Header refactoring, rename FhirRequest to HTTPRequest
This commit is contained in:
parent
b33de12e49
commit
0b45b0b882
|
@ -395,7 +395,7 @@ public class ICD11Generator {
|
||||||
|
|
||||||
|
|
||||||
private JsonObject fetchJson(String source) throws IOException {
|
private JsonObject fetchJson(String source) throws IOException {
|
||||||
HTTPResult res = ManagedWebAccess.builder().withAccept("application/json").withHeader("API-Version", "v2").withHeader("Accept-Language", "en").get(source);
|
HTTPResult res = ManagedWebAccess.builder().withHeader("API-Version", "v2").withHeader("Accept-Language", "en").get(source,"application/json");
|
||||||
res.checkThrowException();
|
res.checkThrowException();
|
||||||
return JsonParser.parseObject(res.getContent());
|
return JsonParser.parseObject(res.getContent());
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,7 +7,7 @@ import org.hl7.fhir.r5.model.Bundle;
|
||||||
import org.hl7.fhir.r5.model.Resource;
|
import org.hl7.fhir.r5.model.Resource;
|
||||||
import org.hl7.fhir.r5.utils.client.EFhirClientException;
|
import org.hl7.fhir.r5.utils.client.EFhirClientException;
|
||||||
import org.hl7.fhir.utilities.ToolingClientLogger;
|
import org.hl7.fhir.utilities.ToolingClientLogger;
|
||||||
import org.hl7.fhir.utilities.http.FhirRequest;
|
import org.hl7.fhir.utilities.http.HTTPRequest;
|
||||||
import org.hl7.fhir.utilities.http.HTTPHeader;
|
import org.hl7.fhir.utilities.http.HTTPHeader;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
@ -40,9 +40,9 @@ public class Client {
|
||||||
.method("OPTIONS", null)
|
.method("OPTIONS", null)
|
||||||
.url(optionsUri.toURL());
|
.url(optionsUri.toURL());
|
||||||
*/
|
*/
|
||||||
FhirRequest request = new FhirRequest()
|
HTTPRequest request = new HTTPRequest()
|
||||||
.withUrl(optionsUri.toURL())
|
.withUrl(optionsUri.toURL())
|
||||||
.withMethod(FhirRequest.HttpMethod.OPTIONS);
|
.withMethod(HTTPRequest.HttpMethod.OPTIONS);
|
||||||
return executeFhirRequest(request, resourceFormat, Collections.emptyList(), message, retryCount, timeout);
|
return executeFhirRequest(request, resourceFormat, Collections.emptyList(), message, retryCount, timeout);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -56,9 +56,9 @@ public class Client {
|
||||||
.url(resourceUri.toURL());
|
.url(resourceUri.toURL());
|
||||||
|
|
||||||
*/
|
*/
|
||||||
FhirRequest request = new FhirRequest()
|
HTTPRequest request = new HTTPRequest()
|
||||||
.withUrl(resourceUri.toURL())
|
.withUrl(resourceUri.toURL())
|
||||||
.withMethod(FhirRequest.HttpMethod.GET);
|
.withMethod(HTTPRequest.HttpMethod.GET);
|
||||||
|
|
||||||
return executeFhirRequest(request, resourceFormat, headers, message, retryCount, timeout);
|
return executeFhirRequest(request, resourceFormat, headers, message, retryCount, timeout);
|
||||||
}
|
}
|
||||||
|
@ -84,9 +84,9 @@ public class Client {
|
||||||
.url(resourceUri.toURL())
|
.url(resourceUri.toURL())
|
||||||
.put(body);
|
.put(body);
|
||||||
*/
|
*/
|
||||||
FhirRequest request = new FhirRequest()
|
HTTPRequest request = new HTTPRequest()
|
||||||
.withUrl(resourceUri.toURL())
|
.withUrl(resourceUri.toURL())
|
||||||
.withMethod(FhirRequest.HttpMethod.PUT)
|
.withMethod(HTTPRequest.HttpMethod.PUT)
|
||||||
.withBody(payload)
|
.withBody(payload)
|
||||||
.withContentType(getContentTypeWithDefaultCharset(resourceFormat));
|
.withContentType(getContentTypeWithDefaultCharset(resourceFormat));
|
||||||
|
|
||||||
|
@ -114,9 +114,9 @@ public class Client {
|
||||||
.url(resourceUri.toURL())
|
.url(resourceUri.toURL())
|
||||||
.post(body);
|
.post(body);
|
||||||
*/
|
*/
|
||||||
FhirRequest request = new FhirRequest()
|
HTTPRequest request = new HTTPRequest()
|
||||||
.withUrl(resourceUri.toURL())
|
.withUrl(resourceUri.toURL())
|
||||||
.withMethod(FhirRequest.HttpMethod.POST)
|
.withMethod(HTTPRequest.HttpMethod.POST)
|
||||||
.withBody(payload)
|
.withBody(payload)
|
||||||
.withContentType(getContentTypeWithDefaultCharset(resourceFormat));
|
.withContentType(getContentTypeWithDefaultCharset(resourceFormat));
|
||||||
|
|
||||||
|
@ -129,9 +129,9 @@ public class Client {
|
||||||
.url(resourceUri.toURL())
|
.url(resourceUri.toURL())
|
||||||
.delete();
|
.delete();
|
||||||
*/
|
*/
|
||||||
FhirRequest request = new FhirRequest()
|
HTTPRequest request = new HTTPRequest()
|
||||||
.withUrl(resourceUri.toURL())
|
.withUrl(resourceUri.toURL())
|
||||||
.withMethod(FhirRequest.HttpMethod.DELETE);
|
.withMethod(HTTPRequest.HttpMethod.DELETE);
|
||||||
return executeFhirRequest(request, null, Collections.emptyList(), null, retryCount, timeout).isSuccessfulRequest();
|
return executeFhirRequest(request, null, Collections.emptyList(), null, retryCount, timeout).isSuccessfulRequest();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -140,9 +140,9 @@ public class Client {
|
||||||
Request.Builder request = new Request.Builder()
|
Request.Builder request = new Request.Builder()
|
||||||
.url(resourceUri.toURL());
|
.url(resourceUri.toURL());
|
||||||
*/
|
*/
|
||||||
FhirRequest request = new FhirRequest()
|
HTTPRequest request = new HTTPRequest()
|
||||||
.withUrl(resourceUri.toURL())
|
.withUrl(resourceUri.toURL())
|
||||||
.withMethod(FhirRequest.HttpMethod.GET);
|
.withMethod(HTTPRequest.HttpMethod.GET);
|
||||||
return executeBundleRequest(request, resourceFormat, Collections.emptyList(), null, retryCount, timeout);
|
return executeBundleRequest(request, resourceFormat, Collections.emptyList(), null, retryCount, timeout);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -159,9 +159,9 @@ public class Client {
|
||||||
.url(resourceUri.toURL())
|
.url(resourceUri.toURL())
|
||||||
.post(body);
|
.post(body);
|
||||||
*/
|
*/
|
||||||
FhirRequest request = new FhirRequest()
|
HTTPRequest request = new HTTPRequest()
|
||||||
.withUrl(resourceUri.toURL())
|
.withUrl(resourceUri.toURL())
|
||||||
.withMethod(FhirRequest.HttpMethod.POST)
|
.withMethod(HTTPRequest.HttpMethod.POST)
|
||||||
.withBody(payload)
|
.withBody(payload)
|
||||||
.withContentType(getContentTypeWithDefaultCharset(resourceFormat));
|
.withContentType(getContentTypeWithDefaultCharset(resourceFormat));
|
||||||
return executeBundleRequest(request, resourceFormat, Collections.emptyList(), null, retryCount, timeout);
|
return executeBundleRequest(request, resourceFormat, Collections.emptyList(), null, retryCount, timeout);
|
||||||
|
@ -180,9 +180,9 @@ public class Client {
|
||||||
.url(resourceUri.toURL())
|
.url(resourceUri.toURL())
|
||||||
.post(body);
|
.post(body);
|
||||||
*/
|
*/
|
||||||
FhirRequest request = new FhirRequest()
|
HTTPRequest request = new HTTPRequest()
|
||||||
.withUrl(resourceUri.toURL())
|
.withUrl(resourceUri.toURL())
|
||||||
.withMethod(FhirRequest.HttpMethod.POST)
|
.withMethod(HTTPRequest.HttpMethod.POST)
|
||||||
.withBody(payload)
|
.withBody(payload)
|
||||||
.withContentType(getContentTypeWithDefaultCharset(resourceFormat));
|
.withContentType(getContentTypeWithDefaultCharset(resourceFormat));
|
||||||
return executeBundleRequest(request, resourceFormat, headers, message, retryCount, timeout);
|
return executeBundleRequest(request, resourceFormat, headers, message, retryCount, timeout);
|
||||||
|
@ -192,7 +192,7 @@ public class Client {
|
||||||
return resourceFormat + ";charset=" + DEFAULT_CHARSET;
|
return resourceFormat + ";charset=" + DEFAULT_CHARSET;
|
||||||
}
|
}
|
||||||
|
|
||||||
public <T extends Resource> Bundle executeBundleRequest(FhirRequest request,
|
public <T extends Resource> Bundle executeBundleRequest(HTTPRequest request,
|
||||||
String resourceFormat,
|
String resourceFormat,
|
||||||
Iterable<HTTPHeader> headers,
|
Iterable<HTTPHeader> headers,
|
||||||
String message,
|
String message,
|
||||||
|
@ -208,7 +208,7 @@ public class Client {
|
||||||
.executeAsBatch();
|
.executeAsBatch();
|
||||||
}
|
}
|
||||||
|
|
||||||
public <T extends Resource> ResourceRequest<T> executeFhirRequest(FhirRequest request,
|
public <T extends Resource> ResourceRequest<T> executeFhirRequest(HTTPRequest request,
|
||||||
String resourceFormat,
|
String resourceFormat,
|
||||||
Iterable<HTTPHeader> headers,
|
Iterable<HTTPHeader> headers,
|
||||||
String message,
|
String message,
|
||||||
|
|
|
@ -1,70 +0,0 @@
|
||||||
package org.hl7.fhir.r5.utils.client.network;
|
|
||||||
|
|
||||||
import okhttp3.*;
|
|
||||||
import okio.Buffer;
|
|
||||||
|
|
||||||
import org.hl7.fhir.utilities.ToolingClientLogger;
|
|
||||||
|
|
||||||
import javax.annotation.Nonnull;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
public class FhirLoggingInterceptor implements Interceptor {
|
|
||||||
|
|
||||||
private ToolingClientLogger logger;
|
|
||||||
|
|
||||||
public FhirLoggingInterceptor(ToolingClientLogger logger) {
|
|
||||||
this.logger = logger;
|
|
||||||
}
|
|
||||||
|
|
||||||
public FhirLoggingInterceptor setLogger(ToolingClientLogger logger) {
|
|
||||||
this.logger = logger;
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Response intercept(@Nonnull Interceptor.Chain chain) throws IOException {
|
|
||||||
// Log Request
|
|
||||||
Request request = chain.request();
|
|
||||||
List<String> hdrs = new ArrayList<>();
|
|
||||||
for (String s : request.headers().toString().split("\\n")) {
|
|
||||||
hdrs.add(s.trim());
|
|
||||||
}
|
|
||||||
byte[] cnt = null;
|
|
||||||
if (request.body() != null) {
|
|
||||||
Buffer buf = new Buffer();
|
|
||||||
request.body().writeTo(buf);
|
|
||||||
cnt = buf.readByteArray();
|
|
||||||
}
|
|
||||||
if (logger != null) {
|
|
||||||
logger.logRequest(request.method(), request.url().toString(), hdrs, cnt);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Log Response
|
|
||||||
Response response = null;
|
|
||||||
response = chain.proceed(chain.request());
|
|
||||||
|
|
||||||
MediaType contentType = null;
|
|
||||||
byte[] bodyBytes = null;
|
|
||||||
if (response.body() != null) {
|
|
||||||
contentType = response.body().contentType();
|
|
||||||
bodyBytes = response.body().bytes();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get Headers as List
|
|
||||||
List<String> headerList = new ArrayList<>();
|
|
||||||
Map<String, List<String>> headerMap = response.headers().toMultimap();
|
|
||||||
headerMap.keySet().forEach(key -> headerMap.get(key).forEach(value -> headerList.add(key + ":" + value)));
|
|
||||||
|
|
||||||
if (logger != null) {
|
|
||||||
long responseTimeInMillis = response.receivedResponseAtMillis() - response.sentRequestAtMillis();
|
|
||||||
logger.logResponse(Integer.toString(response.code()), headerList, bodyBytes, responseTimeInMillis);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Reading byte[] clears body. Need to recreate.
|
|
||||||
ResponseBody body = ResponseBody.create(bodyBytes, contentType);
|
|
||||||
return response.newBuilder().body(body).build();
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,12 +1,10 @@
|
||||||
package org.hl7.fhir.r5.utils.client.network;
|
package org.hl7.fhir.r5.utils.client.network;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
import javax.annotation.Nonnull;
|
|
||||||
|
|
||||||
import okhttp3.*;
|
import okhttp3.*;
|
||||||
import org.apache.commons.lang3.StringUtils;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
import org.hl7.fhir.r5.formats.IParser;
|
import org.hl7.fhir.r5.formats.IParser;
|
||||||
|
@ -21,20 +19,22 @@ import org.hl7.fhir.r5.utils.client.EFhirClientException;
|
||||||
import org.hl7.fhir.r5.utils.client.ResourceFormat;
|
import org.hl7.fhir.r5.utils.client.ResourceFormat;
|
||||||
import org.hl7.fhir.utilities.MimeType;
|
import org.hl7.fhir.utilities.MimeType;
|
||||||
import org.hl7.fhir.utilities.ToolingClientLogger;
|
import org.hl7.fhir.utilities.ToolingClientLogger;
|
||||||
import org.hl7.fhir.utilities.Utilities;
|
|
||||||
import org.hl7.fhir.utilities.http.*;
|
import org.hl7.fhir.utilities.http.*;
|
||||||
import org.hl7.fhir.utilities.xhtml.XhtmlUtils;
|
import org.hl7.fhir.utilities.xhtml.XhtmlUtils;
|
||||||
|
|
||||||
public class FhirRequestBuilder {
|
public class FhirRequestBuilder {
|
||||||
|
|
||||||
|
protected static final String DEFAULT_CHARSET = "UTF-8";
|
||||||
|
|
||||||
protected static final String LOCATION_HEADER = "location";
|
protected static final String LOCATION_HEADER = "location";
|
||||||
protected static final String CONTENT_LOCATION_HEADER = "content-location";
|
protected static final String CONTENT_LOCATION_HEADER = "content-location";
|
||||||
protected static final String DEFAULT_CHARSET = "UTF-8";
|
|
||||||
/**
|
/**
|
||||||
* The singleton instance of the HttpClient, used for all requests.
|
* The singleton instance of the HttpClient, used for all requests.
|
||||||
*/
|
*/
|
||||||
private static OkHttpClient okHttpClient;
|
// private static OkHttpClient okHttpClient;
|
||||||
private final Request.Builder httpRequest;
|
//private final Request.Builder httpRequest;
|
||||||
|
private final HTTPRequest httpRequest;
|
||||||
private String resourceFormat = null;
|
private String resourceFormat = null;
|
||||||
private Iterable<HTTPHeader> headers = null;
|
private Iterable<HTTPHeader> headers = null;
|
||||||
private String message = null;
|
private String message = null;
|
||||||
|
@ -49,71 +49,53 @@ public class FhirRequestBuilder {
|
||||||
private TimeUnit timeoutUnit = TimeUnit.MILLISECONDS;
|
private TimeUnit timeoutUnit = TimeUnit.MILLISECONDS;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* {@link FhirLoggingInterceptor} for log output.
|
* {@link ToolingClientLogger} for log output.
|
||||||
*/
|
*/
|
||||||
private ToolingClientLogger logger = null;
|
private ToolingClientLogger logger = null;
|
||||||
|
|
||||||
private String source;
|
private String source;
|
||||||
|
|
||||||
//TODO this should be the only constructor. There should be no okHttp exposure.
|
//TODO this should be the only constructor. There should be no okHttp exposure.
|
||||||
public FhirRequestBuilder(FhirRequest fhirRequest, String source) {
|
public FhirRequestBuilder(HTTPRequest httpRequest, String source) {
|
||||||
this.source = source;
|
this.source = source;
|
||||||
|
this.httpRequest = httpRequest;
|
||||||
Request.Builder baseRequestBuilder = new Request.Builder();
|
|
||||||
assert fhirRequest.getUrl() != null;
|
|
||||||
baseRequestBuilder.url(fhirRequest.getUrl());
|
|
||||||
|
|
||||||
RequestBody body = fhirRequest.getBody() == null ? null : RequestBody.create(fhirRequest.getBody());
|
|
||||||
this.httpRequest = new Request.Builder()
|
|
||||||
.url(fhirRequest.getUrl())
|
|
||||||
.method(fhirRequest.getMethod().name(), body);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Adds necessary default headers, formatting headers, and any passed in {@link Headers} to the passed in
|
* Adds necessary default headers, formatting headers, and any passed in {@link Headers} to the passed in
|
||||||
* {@link okhttp3.Request.Builder}
|
* {@link Request.Builder}
|
||||||
*
|
*
|
||||||
* @param request {@link okhttp3.Request.Builder} to add headers to.
|
* @param request {@link Request.Builder} to add headers to.
|
||||||
* @param format Expected {@link Resource} format.
|
* @param format Expected {@link Resource} format.
|
||||||
* @param headers Any additional {@link Headers} to add to the request.
|
* @param headers Any additional {@link Headers} to add to the request.
|
||||||
*/
|
*/
|
||||||
protected static void formatHeaders(Request.Builder request, String format, Iterable<HTTPHeader> headers) {
|
protected static HTTPRequest formatHeaders(HTTPRequest request, String format, Iterable<HTTPHeader> headers) {
|
||||||
addDefaultHeaders(request, headers);
|
List<HTTPHeader> allHeaders = new ArrayList<>();
|
||||||
if (format != null) addResourceFormatHeaders(request, format);
|
request.getHeaders().forEach(allHeaders::add);
|
||||||
if (headers != null) addHeaders(request, headers);
|
|
||||||
|
if (format != null) getResourceFormatHeaders(request, format).forEach(allHeaders::add);
|
||||||
|
if (headers != null) headers.forEach(allHeaders::add);
|
||||||
|
return request.withHeaders(allHeaders);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Adds necessary headers for all REST requests.
|
|
||||||
* <li>User-Agent : hapi-fhir-tooling-client</li>
|
|
||||||
*
|
|
||||||
* @param request {@link Request.Builder} to add default headers to.
|
|
||||||
*/
|
|
||||||
protected static void addDefaultHeaders(Request.Builder request, Iterable<HTTPHeader> headers) {
|
|
||||||
boolean hasUserAgent = false;
|
|
||||||
if (headers != null) {
|
|
||||||
for (HTTPHeader header : headers) {
|
|
||||||
if (header.getName().equalsIgnoreCase("User-Agent")) {
|
|
||||||
hasUserAgent = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!hasUserAgent) {
|
|
||||||
request.addHeader("User-Agent", "hapi-fhir-tooling-client");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Adds necessary headers for the given resource format provided.
|
* Adds necessary headers for the given resource format provided.
|
||||||
*
|
*
|
||||||
* @param request {@link Request.Builder} to add default headers to.
|
* @param httpRequest {@link Request.Builder} to add default headers to.
|
||||||
*/
|
*/
|
||||||
protected static void addResourceFormatHeaders(Request.Builder request, String format) {
|
protected static Iterable<HTTPHeader> getResourceFormatHeaders(HTTPRequest httpRequest, String format) {
|
||||||
request.addHeader("Accept", format);
|
List<HTTPHeader> headers = new ArrayList<>();
|
||||||
if (Utilities.existsInList(request.getMethod$okhttp(), "POST", "PUT")) {
|
headers.add(new HTTPHeader("Accept", format));
|
||||||
request.addHeader("Content-Type", format + ";charset=" + DEFAULT_CHARSET);
|
if (httpRequest.getMethod() == HTTPRequest.HttpMethod.PUT
|
||||||
|
|| httpRequest.getMethod() == HTTPRequest.HttpMethod.POST
|
||||||
|
|| httpRequest.getMethod() == HTTPRequest.HttpMethod.PATCH
|
||||||
|
) {
|
||||||
|
headers.add( new HTTPHeader("Content-Type", format + ";charset=" + DEFAULT_CHARSET));
|
||||||
}
|
}
|
||||||
|
return headers;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -127,10 +109,10 @@ public class FhirRequestBuilder {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns true if any of the {@link org.hl7.fhir.r5.model.OperationOutcome.OperationOutcomeIssueComponent} within the
|
* Returns true if any of the {@link OperationOutcome.OperationOutcomeIssueComponent} within the
|
||||||
* provided {@link OperationOutcome} have an {@link org.hl7.fhir.r5.model.OperationOutcome.IssueSeverity} of
|
* provided {@link OperationOutcome} have an {@link OperationOutcome.IssueSeverity} of
|
||||||
* {@link org.hl7.fhir.r5.model.OperationOutcome.IssueSeverity#ERROR} or
|
* {@link OperationOutcome.IssueSeverity#ERROR} or
|
||||||
* {@link org.hl7.fhir.r5.model.OperationOutcome.IssueSeverity#FATAL}
|
* {@link OperationOutcome.IssueSeverity#FATAL}
|
||||||
*
|
*
|
||||||
* @param oo {@link OperationOutcome} to evaluate.
|
* @param oo {@link OperationOutcome} to evaluate.
|
||||||
* @return {@link Boolean#TRUE} if an error exists.
|
* @return {@link Boolean#TRUE} if an error exists.
|
||||||
|
@ -141,23 +123,7 @@ public class FhirRequestBuilder {
|
||||||
|| issue.getSeverity() == OperationOutcome.IssueSeverity.FATAL));
|
|| issue.getSeverity() == OperationOutcome.IssueSeverity.FATAL));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Extracts the 'location' header from the passes in {@link Headers}. If no value for 'location' exists, the
|
|
||||||
* value for 'content-location' is returned. If neither header exists, we return null.
|
|
||||||
*
|
|
||||||
* @param headers {@link Headers} to evaluate
|
|
||||||
* @return {@link String} header value, or null if no location headers are set.
|
|
||||||
*/
|
|
||||||
protected static String getLocationHeader(Headers headers) {
|
|
||||||
Map<String, List<String>> headerMap = headers.toMultimap();
|
|
||||||
if (headerMap.containsKey(LOCATION_HEADER)) {
|
|
||||||
return headerMap.get(LOCATION_HEADER).get(0);
|
|
||||||
} else if (headerMap.containsKey(CONTENT_LOCATION_HEADER)) {
|
|
||||||
return headerMap.get(CONTENT_LOCATION_HEADER).get(0);
|
|
||||||
} else {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected ManagedFhirWebAccessBuilder getManagedWebAccessBuilder() {
|
protected ManagedFhirWebAccessBuilder getManagedWebAccessBuilder() {
|
||||||
return new ManagedFhirWebAccessBuilder("hapi-fhir-tooling-client", null).withRetries(retryCount).withTimeout(timeout, timeoutUnit).withLogger(logger);
|
return new ManagedFhirWebAccessBuilder("hapi-fhir-tooling-client", null).withRetries(retryCount).withTimeout(timeout, timeoutUnit).withLogger(logger);
|
||||||
|
@ -241,20 +207,18 @@ public class FhirRequestBuilder {
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected Request buildRequest() {
|
|
||||||
return httpRequest.build();
|
|
||||||
}
|
|
||||||
|
|
||||||
public <T extends Resource> ResourceRequest<T> execute() throws IOException {
|
public <T extends Resource> ResourceRequest<T> execute() throws IOException {
|
||||||
formatHeaders(httpRequest, resourceFormat, headers);
|
HTTPRequest requestWithHeaders = formatHeaders(httpRequest, resourceFormat, headers);
|
||||||
Response response = getManagedWebAccessBuilder().httpCall(httpRequest);//getHttpClient().newCall(httpRequest.build()).execute();
|
HTTPResult response = getManagedWebAccessBuilder().httpCall(requestWithHeaders);//getHttpClient().newCall(httpRequest.build()).execute();
|
||||||
T resource = unmarshalReference(response, resourceFormat, null);
|
T resource = unmarshalReference(response, resourceFormat, null);
|
||||||
return new ResourceRequest<T>(resource, response.code(), getLocationHeader(response.headers()));
|
return new ResourceRequest<T>(resource, response.getCode(), getLocationHeader(response.getHeaders()));
|
||||||
}
|
}
|
||||||
|
|
||||||
public Bundle executeAsBatch() throws IOException {
|
public Bundle executeAsBatch() throws IOException {
|
||||||
formatHeaders(httpRequest, resourceFormat, null);
|
HTTPRequest requestWithHeaders = formatHeaders(httpRequest, resourceFormat, null);
|
||||||
Response response = getManagedWebAccessBuilder().httpCall(httpRequest);
|
HTTPResult response = getManagedWebAccessBuilder().httpCall(requestWithHeaders);
|
||||||
return unmarshalFeed(response, resourceFormat);
|
return unmarshalFeed(response, resourceFormat);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -262,12 +226,12 @@ public class FhirRequestBuilder {
|
||||||
* Unmarshalls a resource from the response stream.
|
* Unmarshalls a resource from the response stream.
|
||||||
*/
|
*/
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
protected <T extends Resource> T unmarshalReference(Response response, String format, String resourceType) {
|
protected <T extends Resource> T unmarshalReference(HTTPResult response, String format, String resourceType) {
|
||||||
int code = response.code();
|
int code = response.getCode();
|
||||||
boolean ok = code >= 200 && code < 300;
|
boolean ok = code >= 200 && code < 300;
|
||||||
if (response.body() == null) {
|
if (response.getContent() == null) {
|
||||||
if (!ok) {
|
if (!ok) {
|
||||||
throw new EFhirClientException(code, response.message());
|
throw new EFhirClientException(code, response.getMessage());
|
||||||
} else {
|
} else {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
@ -276,9 +240,9 @@ public class FhirRequestBuilder {
|
||||||
|
|
||||||
Resource resource = null;
|
Resource resource = null;
|
||||||
try {
|
try {
|
||||||
body = response.body().string();
|
body = response.getContentAsString();
|
||||||
String ct = response.header("Content-Type");
|
String contentType = HTTPHeaderUtil.getSingleHeader(response.getHeaders(), "Content-Type");
|
||||||
if (ct == null) {
|
if (contentType == null) {
|
||||||
if (ok) {
|
if (ok) {
|
||||||
resource = getParser(format).parse(body);
|
resource = getParser(format).parse(body);
|
||||||
} else {
|
} else {
|
||||||
|
@ -287,10 +251,10 @@ public class FhirRequestBuilder {
|
||||||
resource = OperationOutcomeUtilities.outcomeFromTextError(body);
|
resource = OperationOutcomeUtilities.outcomeFromTextError(body);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (ct.contains(";")) {
|
if (contentType.contains(";")) {
|
||||||
ct = ct.substring(0, ct.indexOf(";"));
|
contentType = contentType.substring(0, contentType.indexOf(";"));
|
||||||
}
|
}
|
||||||
switch (ct) {
|
switch (contentType) {
|
||||||
case "application/json":
|
case "application/json":
|
||||||
case "application/fhir+json":
|
case "application/fhir+json":
|
||||||
if (!format.contains("json")) {
|
if (!format.contains("json")) {
|
||||||
|
@ -310,10 +274,10 @@ public class FhirRequestBuilder {
|
||||||
resource = OperationOutcomeUtilities.outcomeFromTextError(body);
|
resource = OperationOutcomeUtilities.outcomeFromTextError(body);
|
||||||
break;
|
break;
|
||||||
case "text/html" :
|
case "text/html" :
|
||||||
resource = OperationOutcomeUtilities.outcomeFromTextError(XhtmlUtils.convertHtmlToText(response.body().string(), source));
|
resource = OperationOutcomeUtilities.outcomeFromTextError(XhtmlUtils.convertHtmlToText(response.getContentAsString(), source));
|
||||||
break;
|
break;
|
||||||
default: // not sure what else to do?
|
default: // not sure what else to do?
|
||||||
System.out.println("Got content-type '"+ct+"' from "+source);
|
System.out.println("Got content-type '"+contentType+"' from "+source);
|
||||||
System.out.println(body);
|
System.out.println(body);
|
||||||
resource = OperationOutcomeUtilities.outcomeFromTextError(body);
|
resource = OperationOutcomeUtilities.outcomeFromTextError(body);
|
||||||
}
|
}
|
||||||
|
@ -348,7 +312,7 @@ public class FhirRequestBuilder {
|
||||||
/**
|
/**
|
||||||
* Unmarshalls Bundle from response stream.
|
* Unmarshalls Bundle from response stream.
|
||||||
*/
|
*/
|
||||||
protected Bundle unmarshalFeed(Response response, String format) {
|
protected Bundle unmarshalFeed(HTTPResult response, String format) {
|
||||||
return unmarshalReference(response, format, "Bundle");
|
return unmarshalReference(response, format, "Bundle");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -374,4 +338,17 @@ public class FhirRequestBuilder {
|
||||||
throw new EFhirClientException(0, "Invalid format: " + format);
|
throw new EFhirClientException(0, "Invalid format: " + format);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Extracts the 'location' header from. If no value for 'location' exists, the
|
||||||
|
* value for 'content-location' is returned. If neither header exists, we return null.
|
||||||
|
*/
|
||||||
|
protected static String getLocationHeader(Iterable<HTTPHeader> headers) {
|
||||||
|
String locationHeader = HTTPHeaderUtil.getSingleHeader(headers, LOCATION_HEADER);
|
||||||
|
|
||||||
|
if (locationHeader != null) {
|
||||||
|
return locationHeader;
|
||||||
|
}
|
||||||
|
return HTTPHeaderUtil.getSingleHeader(headers, CONTENT_LOCATION_HEADER);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,63 +0,0 @@
|
||||||
package org.hl7.fhir.r5.utils.client.network;
|
|
||||||
|
|
||||||
import okhttp3.Interceptor;
|
|
||||||
import okhttp3.Request;
|
|
||||||
import okhttp3.Response;
|
|
||||||
import javax.annotation.Nonnull;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* An {@link Interceptor} for {@link okhttp3.OkHttpClient} that controls the number of times we retry a to execute a
|
|
||||||
* given request, before reporting a failure. This includes unsuccessful return codes and timeouts.
|
|
||||||
*/
|
|
||||||
public class RetryInterceptor implements Interceptor {
|
|
||||||
|
|
||||||
// Delay between retying failed requests, in millis
|
|
||||||
private final long RETRY_TIME = 2000;
|
|
||||||
|
|
||||||
// Maximum number of times to retry the request before failing
|
|
||||||
private final int maxRetry;
|
|
||||||
|
|
||||||
// Internal counter for tracking the number of times we've tried this request
|
|
||||||
private int retryCounter = 0;
|
|
||||||
|
|
||||||
public RetryInterceptor(int maxRetry) {
|
|
||||||
this.maxRetry = maxRetry;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Response intercept(Interceptor.Chain chain) throws IOException {
|
|
||||||
Request request = chain.request();
|
|
||||||
Response response = null;
|
|
||||||
|
|
||||||
do {
|
|
||||||
try {
|
|
||||||
// If we are retrying a failed request that failed due to a bad response from the server, we must close it first
|
|
||||||
if (response != null) {
|
|
||||||
// System.out.println("Previous " + chain.request().method() + " attempt returned HTTP<" + (response.code())
|
|
||||||
// + "> from url -> " + chain.request().url() + ".");
|
|
||||||
response.close();
|
|
||||||
}
|
|
||||||
// System.out.println(chain.request().method() + " attempt <" + (retryCounter + 1) + "> to url -> " + chain.request().url());
|
|
||||||
response = chain.proceed(request);
|
|
||||||
} catch (IOException e) {
|
|
||||||
try {
|
|
||||||
// Include a small break in between requests.
|
|
||||||
Thread.sleep(RETRY_TIME);
|
|
||||||
} catch (InterruptedException e1) {
|
|
||||||
System.out.println(chain.request().method() + " to url -> " + chain.request().url() + " interrupted on try <" + retryCounter + ">");
|
|
||||||
}
|
|
||||||
} finally {
|
|
||||||
retryCounter++;
|
|
||||||
}
|
|
||||||
} while ((response == null || !response.isSuccessful()) && (retryCounter <= maxRetry + 1));
|
|
||||||
|
|
||||||
/*
|
|
||||||
* if something has gone wrong, and we are unable to complete the request, we still need to initialize the return
|
|
||||||
* response so we don't get a null pointer exception.
|
|
||||||
*/
|
|
||||||
return response != null ? response : chain.proceed(request);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -23,7 +23,7 @@ import org.hl7.fhir.r5.model.TerminologyCapabilities;
|
||||||
import org.hl7.fhir.r5.utils.client.network.Client;
|
import org.hl7.fhir.r5.utils.client.network.Client;
|
||||||
import org.hl7.fhir.r5.utils.client.network.ResourceRequest;
|
import org.hl7.fhir.r5.utils.client.network.ResourceRequest;
|
||||||
|
|
||||||
import org.hl7.fhir.utilities.http.FhirRequest;
|
import org.hl7.fhir.utilities.http.HTTPRequest;
|
||||||
import org.hl7.fhir.utilities.http.HTTPHeader;
|
import org.hl7.fhir.utilities.http.HTTPHeader;
|
||||||
import org.hl7.fhir.utilities.settings.FhirSettings;
|
import org.hl7.fhir.utilities.settings.FhirSettings;
|
||||||
import org.junit.jupiter.api.BeforeEach;
|
import org.junit.jupiter.api.BeforeEach;
|
||||||
|
@ -74,7 +74,7 @@ class FHIRToolingClientTest {
|
||||||
ArgumentMatchers.any(), Mockito.contains("validate"), Mockito.anyLong()))
|
ArgumentMatchers.any(), Mockito.contains("validate"), Mockito.anyLong()))
|
||||||
.thenReturn(new ResourceRequest<>(new OperationOutcome(), 200, "location"));
|
.thenReturn(new ResourceRequest<>(new OperationOutcome(), 200, "location"));
|
||||||
//BUNDLE REQ
|
//BUNDLE REQ
|
||||||
Mockito.when(mockClient.executeBundleRequest(Mockito.any(FhirRequest.class), Mockito.anyString(),
|
Mockito.when(mockClient.executeBundleRequest(Mockito.any(HTTPRequest.class), Mockito.anyString(),
|
||||||
ArgumentMatchers.any(), Mockito.anyString(), Mockito.anyInt(), Mockito.anyLong()))
|
ArgumentMatchers.any(), Mockito.anyString(), Mockito.anyInt(), Mockito.anyLong()))
|
||||||
.thenReturn(generateBundle());
|
.thenReturn(generateBundle());
|
||||||
toolingClient = new FHIRToolingClient(TX_ADDR, "fhir/test-cases");
|
toolingClient = new FHIRToolingClient(TX_ADDR, "fhir/test-cases");
|
||||||
|
|
|
@ -1,40 +1,32 @@
|
||||||
package org.hl7.fhir.r5.utils.client.network;
|
package org.hl7.fhir.r5.utils.client.network;
|
||||||
|
|
||||||
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
import org.hl7.fhir.r5.model.OperationOutcome;
|
import org.hl7.fhir.r5.model.OperationOutcome;
|
||||||
|
import org.hl7.fhir.utilities.http.HTTPHeaderUtil;
|
||||||
|
import org.hl7.fhir.utilities.http.HTTPRequest;
|
||||||
import org.hl7.fhir.utilities.http.HTTPHeader;
|
import org.hl7.fhir.utilities.http.HTTPHeader;
|
||||||
|
import org.hl7.fhir.utilities.http.HTTPResult;
|
||||||
import org.junit.jupiter.api.Assertions;
|
import org.junit.jupiter.api.Assertions;
|
||||||
import org.junit.jupiter.api.DisplayName;
|
import org.junit.jupiter.api.DisplayName;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
import okhttp3.Headers;
|
|
||||||
import okhttp3.Request;
|
import okhttp3.Request;
|
||||||
|
|
||||||
class FhirRequestBuilderTest {
|
class FhirRequestBuilderTest {
|
||||||
|
|
||||||
@Test
|
|
||||||
@DisplayName("Test default headers are added correctly.")
|
|
||||||
void addDefaultHeaders() {
|
|
||||||
Request.Builder request = new Request.Builder().url("http://www.google.com");
|
|
||||||
FhirRequestBuilder.addDefaultHeaders(request, null);
|
|
||||||
|
|
||||||
Map<String, List<String>> headersMap = request.build().headers().toMultimap();
|
|
||||||
Assertions.assertNotNull(headersMap.get("User-Agent"), "User-Agent header null.");
|
|
||||||
Assertions.assertEquals("hapi-fhir-tooling-client", headersMap.get("User-Agent").get(0),
|
|
||||||
"User-Agent header not populated with expected value \"hapi-fhir-tooling-client\".");
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@DisplayName("Test resource format headers are added correctly (GET).")
|
@DisplayName("Test resource format headers are added correctly (GET).")
|
||||||
void addResourceFormatHeadersGET() {
|
void addResourceFormatHeadersGET() {
|
||||||
|
//FIXME tested here. Should get list of HTTPHeader.
|
||||||
String testFormat = "yaml";
|
String testFormat = "yaml";
|
||||||
Request.Builder request = new Request.Builder().url("http://www.google.com");
|
HTTPRequest request = new HTTPRequest().withUrl("http://www.google.com").withMethod(HTTPRequest.HttpMethod.GET);
|
||||||
request.setMethod$okhttp("GET");
|
|
||||||
FhirRequestBuilder.addResourceFormatHeaders(request, testFormat);
|
|
||||||
|
|
||||||
Map<String, List<String>> headersMap = request.build().headers().toMultimap();
|
Iterable<HTTPHeader> headers = FhirRequestBuilder.getResourceFormatHeaders(request, testFormat);
|
||||||
|
|
||||||
|
Map<String, List<String>> headersMap = HTTPHeaderUtil.getMultimap(headers);
|
||||||
Assertions.assertNotNull(headersMap.get("Accept"), "Accept header null.");
|
Assertions.assertNotNull(headersMap.get("Accept"), "Accept header null.");
|
||||||
Assertions.assertEquals(testFormat, headersMap.get("Accept").get(0),
|
Assertions.assertEquals(testFormat, headersMap.get("Accept").get(0),
|
||||||
"Accept header not populated with expected value " + testFormat + ".");
|
"Accept header not populated with expected value " + testFormat + ".");
|
||||||
|
@ -45,12 +37,13 @@ class FhirRequestBuilderTest {
|
||||||
@Test
|
@Test
|
||||||
@DisplayName("Test resource format headers are added correctly (POST).")
|
@DisplayName("Test resource format headers are added correctly (POST).")
|
||||||
void addResourceFormatHeadersPOST() {
|
void addResourceFormatHeadersPOST() {
|
||||||
|
//FIXME tested here. Should get list of HTTPHeader.
|
||||||
String testFormat = "yaml";
|
String testFormat = "yaml";
|
||||||
Request.Builder request = new Request.Builder().url("http://www.google.com");
|
HTTPRequest request = new HTTPRequest().withUrl("http://www.google.com").withMethod(HTTPRequest.HttpMethod.POST);
|
||||||
request.setMethod$okhttp("POST");
|
|
||||||
FhirRequestBuilder.addResourceFormatHeaders(request, testFormat);
|
|
||||||
|
|
||||||
Map<String, List<String>> headersMap = request.build().headers().toMultimap();
|
Iterable<HTTPHeader> headers = FhirRequestBuilder.getResourceFormatHeaders(request, testFormat);
|
||||||
|
|
||||||
|
Map<String, List<String>> headersMap = HTTPHeaderUtil.getMultimap(headers);
|
||||||
Assertions.assertNotNull(headersMap.get("Accept"), "Accept header null.");
|
Assertions.assertNotNull(headersMap.get("Accept"), "Accept header null.");
|
||||||
Assertions.assertEquals(testFormat, headersMap.get("Accept").get(0),
|
Assertions.assertEquals(testFormat, headersMap.get("Accept").get(0),
|
||||||
"Accept header not populated with expected value " + testFormat + ".");
|
"Accept header not populated with expected value " + testFormat + ".");
|
||||||
|
@ -63,6 +56,7 @@ class FhirRequestBuilderTest {
|
||||||
@Test
|
@Test
|
||||||
@DisplayName("Test a list of provided headers are added correctly.")
|
@DisplayName("Test a list of provided headers are added correctly.")
|
||||||
void addHeaders() {
|
void addHeaders() {
|
||||||
|
//FIXME tested here. Should get list of HTTPHeader.
|
||||||
String headerName1 = "headerName1";
|
String headerName1 = "headerName1";
|
||||||
String headerValue1 = "headerValue1";
|
String headerValue1 = "headerValue1";
|
||||||
String headerName2 = "headerName2";
|
String headerName2 = "headerName2";
|
||||||
|
@ -74,7 +68,7 @@ class FhirRequestBuilderTest {
|
||||||
);
|
);
|
||||||
|
|
||||||
Request.Builder request = new Request.Builder().url("http://www.google.com");
|
Request.Builder request = new Request.Builder().url("http://www.google.com");
|
||||||
FhirRequestBuilder.addHeaders(request, headers);
|
headers.forEach(header -> request.addHeader(header.getName(), header.getValue()));
|
||||||
|
|
||||||
Map<String, List<String>> headersMap = request.build().headers().toMultimap();
|
Map<String, List<String>> headersMap = request.build().headers().toMultimap();
|
||||||
Assertions.assertNotNull(headersMap.get(headerName1), headerName1 + " header null.");
|
Assertions.assertNotNull(headersMap.get(headerName1), headerName1 + " header null.");
|
||||||
|
@ -121,19 +115,22 @@ class FhirRequestBuilderTest {
|
||||||
@DisplayName("Test that getLocationHeader returns header for 'location'.")
|
@DisplayName("Test that getLocationHeader returns header for 'location'.")
|
||||||
void getLocationHeaderWhenOnlyLocationIsSet() {
|
void getLocationHeaderWhenOnlyLocationIsSet() {
|
||||||
final String expectedLocationHeader = "location_header_value";
|
final String expectedLocationHeader = "location_header_value";
|
||||||
Headers headers = new Headers.Builder()
|
HTTPResult result = new HTTPResult("source",
|
||||||
.add(FhirRequestBuilder.LOCATION_HEADER, expectedLocationHeader)
|
200,
|
||||||
.build();
|
"message",
|
||||||
Assertions.assertEquals(expectedLocationHeader, FhirRequestBuilder.getLocationHeader(headers));
|
"contentType",
|
||||||
|
new byte[0],
|
||||||
|
List.of(new HTTPHeader(FhirRequestBuilder.LOCATION_HEADER, expectedLocationHeader)));
|
||||||
|
|
||||||
|
Assertions.assertEquals(expectedLocationHeader, FhirRequestBuilder.getLocationHeader(result.getHeaders()));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@DisplayName("Test that getLocationHeader returns header for 'content-location'.")
|
@DisplayName("Test that getLocationHeader returns header for 'content-location'.")
|
||||||
void getLocationHeaderWhenOnlyContentLocationIsSet() {
|
void getLocationHeaderWhenOnlyContentLocationIsSet() {
|
||||||
final String expectedContentLocationHeader = "content_location_header_value";
|
final String expectedContentLocationHeader = "content_location_header_value";
|
||||||
Headers headers = new Headers.Builder()
|
Iterable<HTTPHeader> headers = List.of(new HTTPHeader(FhirRequestBuilder.CONTENT_LOCATION_HEADER, expectedContentLocationHeader));
|
||||||
.add(FhirRequestBuilder.CONTENT_LOCATION_HEADER, expectedContentLocationHeader)
|
|
||||||
.build();
|
|
||||||
Assertions.assertEquals(expectedContentLocationHeader, FhirRequestBuilder.getLocationHeader(headers));
|
Assertions.assertEquals(expectedContentLocationHeader, FhirRequestBuilder.getLocationHeader(headers));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -142,18 +139,18 @@ class FhirRequestBuilderTest {
|
||||||
void getLocationHeaderWhenLocationAndContentLocationAreSet() {
|
void getLocationHeaderWhenLocationAndContentLocationAreSet() {
|
||||||
final String expectedLocationHeader = "location_header_value";
|
final String expectedLocationHeader = "location_header_value";
|
||||||
final String expectedContentLocationHeader = "content_location_header_value";
|
final String expectedContentLocationHeader = "content_location_header_value";
|
||||||
Headers headers = new Headers.Builder()
|
|
||||||
.add(FhirRequestBuilder.LOCATION_HEADER, expectedLocationHeader)
|
Iterable<HTTPHeader> headers = List.of(
|
||||||
.add(FhirRequestBuilder.CONTENT_LOCATION_HEADER, expectedContentLocationHeader)
|
new HTTPHeader(FhirRequestBuilder.LOCATION_HEADER, expectedLocationHeader),
|
||||||
.build();
|
new HTTPHeader(FhirRequestBuilder.CONTENT_LOCATION_HEADER, expectedContentLocationHeader)
|
||||||
|
);
|
||||||
|
|
||||||
Assertions.assertEquals(expectedLocationHeader, FhirRequestBuilder.getLocationHeader(headers));
|
Assertions.assertEquals(expectedLocationHeader, FhirRequestBuilder.getLocationHeader(headers));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@DisplayName("Test that getLocationHeader returns null when no location available.")
|
@DisplayName("Test that getLocationHeader returns null when no location available.")
|
||||||
void getLocationHeaderWhenNoLocationSet() {
|
void getLocationHeaderWhenNoLocationSet() {
|
||||||
Headers headers = new Headers.Builder()
|
Assertions.assertNull(FhirRequestBuilder.getLocationHeader(Collections.emptyList()));
|
||||||
.build();
|
|
||||||
Assertions.assertNull(FhirRequestBuilder.getLocationHeader(headers));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -1,34 +0,0 @@
|
||||||
package org.hl7.fhir.utilities.http;
|
|
||||||
|
|
||||||
import lombok.AllArgsConstructor;
|
|
||||||
import lombok.Getter;
|
|
||||||
import lombok.With;
|
|
||||||
|
|
||||||
import javax.annotation.Nullable;
|
|
||||||
import java.net.URL;
|
|
||||||
|
|
||||||
@AllArgsConstructor
|
|
||||||
public class FhirRequest {
|
|
||||||
|
|
||||||
public FhirRequest() {
|
|
||||||
url = null;
|
|
||||||
method = HttpMethod.GET;
|
|
||||||
body = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public enum HttpMethod {
|
|
||||||
GET, POST, PUT, DELETE, OPTIONS, HEAD, PATCH
|
|
||||||
}
|
|
||||||
|
|
||||||
@With @Getter @Nullable
|
|
||||||
private final URL url;
|
|
||||||
|
|
||||||
@With @Getter
|
|
||||||
private HttpMethod method;
|
|
||||||
|
|
||||||
@With @Getter @Nullable
|
|
||||||
private byte[] body;
|
|
||||||
|
|
||||||
@With @Getter @Nullable
|
|
||||||
private String contentType;
|
|
||||||
}
|
|
|
@ -0,0 +1,45 @@
|
||||||
|
package org.hl7.fhir.utilities.http;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
public class HTTPHeaderUtil {
|
||||||
|
|
||||||
|
public static final String USER_AGENT = "User-Agent";
|
||||||
|
|
||||||
|
|
||||||
|
public static Map<String, List<String>> getMultimap(Iterable<HTTPHeader> headers) {
|
||||||
|
Map<String, List<String>> result = new HashMap<>();
|
||||||
|
if (headers != null) {
|
||||||
|
for (HTTPHeader header : headers) {
|
||||||
|
List<String> values = result.getOrDefault(header.getName(), new ArrayList<>());
|
||||||
|
values.add(header.getValue());
|
||||||
|
result.put(header.getName(), values);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Iterable<String> getHeaders(Iterable<HTTPHeader> headers, String key) {
|
||||||
|
List<String> result = new ArrayList<>();
|
||||||
|
if (headers != null) {
|
||||||
|
for (HTTPHeader header : headers) {
|
||||||
|
if (header.getName().equalsIgnoreCase(key)) {
|
||||||
|
result.add(header.getValue());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String getSingleHeader(Iterable<HTTPHeader> headers, String key) {
|
||||||
|
for (HTTPHeader header : headers) {
|
||||||
|
if (header.getName().equalsIgnoreCase(key)) {
|
||||||
|
return header.getValue();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,54 @@
|
||||||
|
package org.hl7.fhir.utilities.http;
|
||||||
|
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.With;
|
||||||
|
|
||||||
|
import javax.annotation.Nonnull;
|
||||||
|
import javax.annotation.Nullable;
|
||||||
|
import java.net.MalformedURLException;
|
||||||
|
import java.net.URL;
|
||||||
|
import java.util.Collections;
|
||||||
|
|
||||||
|
@AllArgsConstructor
|
||||||
|
public class HTTPRequest {
|
||||||
|
|
||||||
|
public HTTPRequest() {
|
||||||
|
url = null;
|
||||||
|
method = HttpMethod.GET;
|
||||||
|
body = null;
|
||||||
|
contentType = null;
|
||||||
|
headers = Collections.emptyList();
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum HttpMethod {
|
||||||
|
GET, POST, PUT, DELETE, OPTIONS, HEAD, PATCH
|
||||||
|
}
|
||||||
|
|
||||||
|
@Getter @Nullable
|
||||||
|
private final URL url;
|
||||||
|
|
||||||
|
public HTTPRequest withUrl(URL url) {
|
||||||
|
return new HTTPRequest(url, method, body, contentType, headers);
|
||||||
|
}
|
||||||
|
|
||||||
|
public HTTPRequest withUrl(String url) {
|
||||||
|
try {
|
||||||
|
return withUrl(new URL(url));
|
||||||
|
} catch (MalformedURLException e) {
|
||||||
|
throw new IllegalArgumentException("Invalid URL: " + url, e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@With @Getter
|
||||||
|
private final HttpMethod method;
|
||||||
|
|
||||||
|
@With @Getter @Nullable
|
||||||
|
private final byte[] body;
|
||||||
|
|
||||||
|
@With @Getter @Nullable
|
||||||
|
private final String contentType;
|
||||||
|
|
||||||
|
@With @Getter @Nonnull
|
||||||
|
private final Iterable<HTTPHeader> headers;
|
||||||
|
}
|
|
@ -2,39 +2,40 @@ package org.hl7.fhir.utilities.http;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.nio.charset.StandardCharsets;
|
import java.nio.charset.StandardCharsets;
|
||||||
|
import java.util.*;
|
||||||
|
|
||||||
|
import lombok.Getter;
|
||||||
import org.hl7.fhir.utilities.TextFile;
|
import org.hl7.fhir.utilities.TextFile;
|
||||||
import org.hl7.fhir.utilities.Utilities;
|
import org.hl7.fhir.utilities.Utilities;
|
||||||
|
|
||||||
public class HTTPResult {
|
public class HTTPResult {
|
||||||
private int code;
|
|
||||||
private String contentType;
|
|
||||||
private byte[] content;
|
|
||||||
private String source;
|
|
||||||
private String message;
|
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
private final int code;
|
||||||
|
@Getter
|
||||||
|
private final String contentType;
|
||||||
|
@Getter
|
||||||
|
private final byte[] content;
|
||||||
|
@Getter
|
||||||
|
private final String source;
|
||||||
|
@Getter
|
||||||
|
private final String message;
|
||||||
|
@Getter
|
||||||
|
private final Iterable<HTTPHeader> headers;
|
||||||
|
|
||||||
public HTTPResult(String source, int code, String message, String contentType, byte[] content) {
|
public HTTPResult(String source, int code, String message, String contentType, byte[] content) {
|
||||||
|
this(source, code, message, contentType, content, Collections.emptyList());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public HTTPResult(String source, int code, String message, String contentType, byte[] content, Iterable<HTTPHeader> headers) {
|
||||||
super();
|
super();
|
||||||
this.source = source;
|
this.source = source;
|
||||||
this.code = code;
|
this.code = code;
|
||||||
this.contentType = contentType;
|
this.contentType = contentType;
|
||||||
this.content = content;
|
this.content = content;
|
||||||
this.message = message;
|
this.message = message;
|
||||||
}
|
this.headers = headers;
|
||||||
|
|
||||||
public int getCode() {
|
|
||||||
return code;
|
|
||||||
}
|
|
||||||
public String getContentType() {
|
|
||||||
return contentType;
|
|
||||||
}
|
|
||||||
public byte[] getContent() {
|
|
||||||
return content;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getSource() {
|
|
||||||
return source;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void checkThrowException() throws IOException {
|
public void checkThrowException() throws IOException {
|
||||||
|
@ -52,10 +53,6 @@ public class HTTPResult {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getMessage() {
|
|
||||||
return message;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getContentAsString() {
|
public String getContentAsString() {
|
||||||
return new String(content, StandardCharsets.UTF_8);
|
return new String(content, StandardCharsets.UTF_8);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
package org.hl7.fhir.utilities.http;
|
package org.hl7.fhir.utilities.http;
|
||||||
|
|
||||||
import lombok.With;
|
|
||||||
import okhttp3.*;
|
import okhttp3.*;
|
||||||
import org.hl7.fhir.utilities.ToolingClientLogger;
|
import org.hl7.fhir.utilities.ToolingClientLogger;
|
||||||
import org.hl7.fhir.utilities.http.okhttpimpl.LoggingInterceptor;
|
import org.hl7.fhir.utilities.http.okhttpimpl.LoggingInterceptor;
|
||||||
|
@ -8,8 +7,8 @@ import org.hl7.fhir.utilities.http.okhttpimpl.ProxyAuthenticator;
|
||||||
import org.hl7.fhir.utilities.http.okhttpimpl.RetryInterceptor;
|
import org.hl7.fhir.utilities.http.okhttpimpl.RetryInterceptor;
|
||||||
import org.hl7.fhir.utilities.settings.ServerDetailsPOJO;
|
import org.hl7.fhir.utilities.settings.ServerDetailsPOJO;
|
||||||
|
|
||||||
import javax.annotation.Nonnull;
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
|
@ -49,25 +48,88 @@ public class ManagedFhirWebAccessBuilder extends ManagedWebAccessBuilderBase<Man
|
||||||
super(userAgent, serverAuthDetails);
|
super(userAgent, serverAuthDetails);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void setHeaders(Request.Builder httpRequest) {
|
protected HTTPRequest httpRequestWithDefaultHeaders(HTTPRequest request) {
|
||||||
for (Map.Entry<String, String> entry : this.getHeaders().entrySet()) {
|
List<HTTPHeader> headers = new ArrayList<>();
|
||||||
httpRequest.header(entry.getKey(), entry.getValue());
|
if (HTTPHeaderUtil.getSingleHeader(request.getHeaders(), HTTPHeaderUtil.USER_AGENT) == null) {
|
||||||
|
headers.add(new HTTPHeader(HTTPHeaderUtil.USER_AGENT, getUserAgent()));
|
||||||
}
|
}
|
||||||
|
request.getHeaders().forEach(headers::add);
|
||||||
|
return request.withHeaders(headers);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Response httpCall(Request.Builder httpRequest) throws IOException {
|
protected HTTPRequest requestWithManagedHeaders(HTTPRequest httpRequest) {
|
||||||
|
HTTPRequest requestWithDefaultHeaders = httpRequestWithDefaultHeaders(httpRequest);
|
||||||
|
|
||||||
|
List<HTTPHeader> headers = new ArrayList<>();
|
||||||
|
requestWithDefaultHeaders.getHeaders().forEach(headers::add);
|
||||||
|
|
||||||
|
for (Map.Entry<String, String> entry : this.getHeaders().entrySet()) {
|
||||||
|
headers.add(new HTTPHeader(entry.getKey(), entry.getValue()));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (getAuthenticationMode() != null) {
|
||||||
|
if (getAuthenticationMode() != HTTPAuthenticationMode.NONE) {
|
||||||
|
switch (getAuthenticationMode()) {
|
||||||
|
case BASIC:
|
||||||
|
final String basicCredential = Credentials.basic(getUsername(), getPassword());
|
||||||
|
headers.add(new HTTPHeader("Authorization", basicCredential));
|
||||||
|
break;
|
||||||
|
case TOKEN:
|
||||||
|
String tokenCredential = "Bearer " + new String(getToken());
|
||||||
|
headers.add(new HTTPHeader("Authorization", tokenCredential));
|
||||||
|
break;
|
||||||
|
case APIKEY:
|
||||||
|
String apiKeyCredential = " " + new String(getToken());
|
||||||
|
headers.add(new HTTPHeader("Api-Key", apiKeyCredential));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
ServerDetailsPOJO settings = ManagedWebAccessUtils.getServer(httpRequest.getUrl().toString(), getServerAuthDetails());
|
||||||
|
if (settings != null) {
|
||||||
|
switch (settings.getAuthenticationType()) {
|
||||||
|
case "basic":
|
||||||
|
final String basicCredential = Credentials.basic(settings.getUsername(), settings.getPassword());
|
||||||
|
headers.add(new HTTPHeader("Authorization", basicCredential));
|
||||||
|
break;
|
||||||
|
case "token":
|
||||||
|
String tokenCredential = "Bearer " + settings.getToken();
|
||||||
|
headers.add(new HTTPHeader("Authorization", tokenCredential));
|
||||||
|
break;
|
||||||
|
case "apikey":
|
||||||
|
String apiKeyCredential = new String(settings.getToken());
|
||||||
|
headers.add(new HTTPHeader("Api-Key", apiKeyCredential));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return httpRequest.withHeaders(headers);
|
||||||
|
}
|
||||||
|
|
||||||
|
public HTTPResult httpCall(HTTPRequest httpRequest) throws IOException {
|
||||||
switch (ManagedWebAccess.getAccessPolicy()) {
|
switch (ManagedWebAccess.getAccessPolicy()) {
|
||||||
case DIRECT:
|
case DIRECT:
|
||||||
|
|
||||||
|
HTTPRequest httpRequestWithDirectHeaders = requestWithManagedHeaders(httpRequest);
|
||||||
|
assert httpRequestWithDirectHeaders.getUrl() != null;
|
||||||
|
|
||||||
|
RequestBody body = httpRequestWithDirectHeaders.getBody() == null ? null : RequestBody.create(httpRequestWithDirectHeaders.getBody());
|
||||||
|
Request.Builder requestBuilder = new Request.Builder()
|
||||||
|
.url(httpRequestWithDirectHeaders.getUrl())
|
||||||
|
.method(httpRequestWithDirectHeaders.getMethod().name(), body);
|
||||||
|
|
||||||
OkHttpClient okHttpClient = getOkHttpClient();
|
OkHttpClient okHttpClient = getOkHttpClient();
|
||||||
//TODO check and throw based on httpRequest:
|
//TODO check and throw based on httpRequest:
|
||||||
// if (!ManagedWebAccess.inAllowedPaths(url)) {
|
// if (!ManagedWebAccess.inAllowedPaths(url)) {
|
||||||
// throw new IOException("The pathname '"+url+"' cannot be accessed by policy");
|
// throw new IOException("The pathname '"+url+"' cannot be accessed by policy");
|
||||||
// }
|
// }
|
||||||
//TODO add auth headers to httpRequest
|
//TODO add auth headers to httpRequest
|
||||||
return okHttpClient.newCall(httpRequest.build()).execute();
|
Response response = okHttpClient.newCall(requestBuilder.build()).execute();
|
||||||
|
return getHTTPResult(response);
|
||||||
case MANAGED:
|
case MANAGED:
|
||||||
setHeaders(httpRequest);
|
HTTPRequest httpRequestWithManagedHeaders = requestWithManagedHeaders(httpRequest);
|
||||||
return ManagedWebAccess.getFhirWebAccessor().httpCall(httpRequest);
|
assert httpRequestWithManagedHeaders.getUrl() != null;
|
||||||
|
return ManagedWebAccess.getFhirWebAccessor().httpCall(httpRequestWithManagedHeaders);
|
||||||
case PROHIBITED:
|
case PROHIBITED:
|
||||||
throw new IOException("Access to the internet is not allowed by local security policy");
|
throw new IOException("Access to the internet is not allowed by local security policy");
|
||||||
default:
|
default:
|
||||||
|
@ -75,6 +137,10 @@ public class ManagedFhirWebAccessBuilder extends ManagedWebAccessBuilderBase<Man
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private HTTPResult getHTTPResult(Response execute) throws IOException {
|
||||||
|
return new HTTPResult(execute.request().url().toString(), execute.code(), execute.message(), execute.header("Content-Type"), execute.body() != null ? execute.body().bytes() : null);
|
||||||
|
}
|
||||||
|
|
||||||
private OkHttpClient getOkHttpClient() {
|
private OkHttpClient getOkHttpClient() {
|
||||||
if (okHttpClient == null) {
|
if (okHttpClient == null) {
|
||||||
okHttpClient = new OkHttpClient();
|
okHttpClient = new OkHttpClient();
|
||||||
|
|
|
@ -31,26 +31,18 @@ package org.hl7.fhir.utilities.http;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
import java.io.File;
|
|
||||||
import java.io.FileInputStream;
|
|
||||||
import java.io.FileNotFoundException;
|
|
||||||
import java.io.FileOutputStream;
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
|
||||||
import java.nio.file.Path;
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
import okhttp3.Request;
|
|
||||||
import okhttp3.Response;
|
import okhttp3.Response;
|
||||||
import org.hl7.fhir.utilities.Utilities;
|
|
||||||
import org.hl7.fhir.utilities.settings.ServerDetailsPOJO;
|
import org.hl7.fhir.utilities.settings.ServerDetailsPOJO;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* see security.md - manages access to the local file system by the FHIR HAPI Core library
|
* see security.md - manages access to the local file system by the FHIR HAPI Core library
|
||||||
*
|
* <p/>
|
||||||
* By using accessPolicy, allowedDomains and accessor, a host java application can control
|
* By using accessPolicy, allowedDomains and accessor, a host java application can control
|
||||||
* whether this library has direct access to the web (and which domains it is allowed to access),
|
* whether this library has direct access to the web (and which domains it is allowed to access),
|
||||||
* or whether the host application provides controlled access, or whether no access is allowed at all
|
* or whether the host application provides controlled access, or whether no access is allowed at all
|
||||||
|
@ -68,7 +60,7 @@ public class ManagedWebAccess {
|
||||||
}
|
}
|
||||||
|
|
||||||
public interface IFhirWebAccessor {
|
public interface IFhirWebAccessor {
|
||||||
Response httpCall(Request.Builder httpRequest);
|
HTTPResult httpCall(HTTPRequest httpRequest);
|
||||||
}
|
}
|
||||||
|
|
||||||
public enum WebAccessPolicy {
|
public enum WebAccessPolicy {
|
||||||
|
@ -133,12 +125,11 @@ public class ManagedWebAccess {
|
||||||
return builder().post(url, content, contentType, accept);
|
return builder().post(url, content, contentType, accept);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public static HTTPResult put(String url, byte[] content, String contentType, String accept) throws IOException {
|
public static HTTPResult put(String url, byte[] content, String contentType, String accept) throws IOException {
|
||||||
return builder().put(url, content, contentType, accept);
|
return builder().put(url, content, contentType, accept);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Response httpCall(FhirRequest httpRequest) throws IOException {
|
public static HTTPResult httpCall(HTTPRequest httpRequest) throws IOException {
|
||||||
return fhirBuilder().httpCall(httpRequest);
|
return fhirBuilder().httpCall(httpRequest);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -44,6 +44,11 @@ public class ManagedWebAccessBuilder extends ManagedWebAccessBuilderBase<Managed
|
||||||
throw new IOException("The pathname '"+url+"' cannot be accessed by policy");
|
throw new IOException("The pathname '"+url+"' cannot be accessed by policy");
|
||||||
}
|
}
|
||||||
SimpleHTTPClient client = new SimpleHTTPClient();
|
SimpleHTTPClient client = new SimpleHTTPClient();
|
||||||
|
|
||||||
|
for (Map.Entry<String, String> entry : this.getHeaders().entrySet()) {
|
||||||
|
client.addHeader(entry.getKey(), entry.getValue());
|
||||||
|
}
|
||||||
|
|
||||||
if (getUserAgent() != null) {
|
if (getUserAgent() != null) {
|
||||||
client.addHeader("User-Agent", getUserAgent());
|
client.addHeader("User-Agent", getUserAgent());
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,7 +22,7 @@ public abstract class ManagedWebAccessBuilderBase<B extends ManagedWebAccessBuil
|
||||||
@Getter
|
@Getter
|
||||||
private final List<ServerDetailsPOJO> serverAuthDetails;
|
private final List<ServerDetailsPOJO> serverAuthDetails;
|
||||||
@Getter
|
@Getter
|
||||||
private Map<String, String> headers = new HashMap<String, String>();
|
private final Map<String, String> headers = new HashMap<>();
|
||||||
|
|
||||||
public ManagedWebAccessBuilderBase(String userAgent, List<ServerDetailsPOJO> serverAuthDetails) {
|
public ManagedWebAccessBuilderBase(String userAgent, List<ServerDetailsPOJO> serverAuthDetails) {
|
||||||
this.userAgent = userAgent;
|
this.userAgent = userAgent;
|
||||||
|
|
|
@ -20,27 +20,10 @@ import lombok.Setter;
|
||||||
|
|
||||||
public class SimpleHTTPClient {
|
public class SimpleHTTPClient {
|
||||||
|
|
||||||
|
|
||||||
public static class Header {
|
|
||||||
private String name;
|
|
||||||
private String value;
|
|
||||||
public Header(String name, String value) {
|
|
||||||
super();
|
|
||||||
this.name = name;
|
|
||||||
this.value = value;
|
|
||||||
}
|
|
||||||
public String getName() {
|
|
||||||
return name;
|
|
||||||
}
|
|
||||||
public String getValue() {
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static final int MAX_REDIRECTS = 5;
|
private static final int MAX_REDIRECTS = 5;
|
||||||
private static int counter = 1;
|
private static int counter = 1;
|
||||||
|
|
||||||
private List<Header> headers = new ArrayList<>();
|
private List<HTTPHeader> headers = new ArrayList<>();
|
||||||
|
|
||||||
@Getter @Setter
|
@Getter @Setter
|
||||||
private HTTPAuthenticationMode authenticationMode;
|
private HTTPAuthenticationMode authenticationMode;
|
||||||
|
@ -58,7 +41,7 @@ public class SimpleHTTPClient {
|
||||||
private String apiKey;
|
private String apiKey;
|
||||||
|
|
||||||
public void addHeader(String name, String value) {
|
public void addHeader(String name, String value) {
|
||||||
headers.add(new Header(name, value));
|
headers.add(new HTTPHeader(name, value));
|
||||||
}
|
}
|
||||||
|
|
||||||
public HTTPResult get(String url) throws IOException {
|
public HTTPResult get(String url) throws IOException {
|
||||||
|
@ -114,8 +97,8 @@ public class SimpleHTTPClient {
|
||||||
|
|
||||||
private void setHeaders(HttpURLConnection c) {
|
private void setHeaders(HttpURLConnection c) {
|
||||||
if (headers != null) {
|
if (headers != null) {
|
||||||
for (Header h : headers) {
|
for (HTTPHeader header : headers) {
|
||||||
c.setRequestProperty(h.getName(), h.getValue());
|
c.setRequestProperty(header.getName(), header.getValue());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
c.setConnectTimeout(15000);
|
c.setConnectTimeout(15000);
|
||||||
|
|
|
@ -0,0 +1,42 @@
|
||||||
|
package org.hl7.fhir.utilities.http;
|
||||||
|
|
||||||
|
import org.junit.jupiter.api.Assertions;
|
||||||
|
import org.junit.jupiter.api.DisplayName;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
|
public class ManagedFhirWebAccessBuilderTests {
|
||||||
|
final String expectedUserAgent = "dummy-agent";
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@DisplayName("Test default headers are added correctly.")
|
||||||
|
void addDefaultAgentHeader() {
|
||||||
|
// FIXME move to ManagedFhirWebAccessBuilder
|
||||||
|
HTTPRequest request = new HTTPRequest().withUrl("http://www.google.com");
|
||||||
|
|
||||||
|
ManagedFhirWebAccessBuilder builder = new ManagedFhirWebAccessBuilder(expectedUserAgent, null);
|
||||||
|
|
||||||
|
HTTPRequest requestWithDefaultHeaders = builder.httpRequestWithDefaultHeaders(request);
|
||||||
|
assertRequestContainsExpectedAgentHeader(requestWithDefaultHeaders);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@DisplayName("Test default headers are added correctly.")
|
||||||
|
void addDefaultBasicHeader() {
|
||||||
|
// FIXME move to ManagedFhirWebAccessBuilder
|
||||||
|
HTTPRequest request = new HTTPRequest().withUrl("http://www.google.com");
|
||||||
|
|
||||||
|
ManagedFhirWebAccessBuilder builder = new ManagedFhirWebAccessBuilder(expectedUserAgent, null)
|
||||||
|
.withBasicAuth("dummy-user", "dummy-password");
|
||||||
|
|
||||||
|
HTTPRequest requestWithManagedHeaders = builder.requestWithManagedHeaders(request);
|
||||||
|
assertRequestContainsExpectedAgentHeader(requestWithManagedHeaders);
|
||||||
|
|
||||||
|
Assertions.assertNotNull(HTTPHeaderUtil.getSingleHeader(requestWithManagedHeaders.getHeaders(),"Authorization"), "Authorization header null.");
|
||||||
|
}
|
||||||
|
|
||||||
|
private void assertRequestContainsExpectedAgentHeader(HTTPRequest requestWithDefaultHeaders) {
|
||||||
|
Assertions.assertNotNull(HTTPHeaderUtil.getSingleHeader(requestWithDefaultHeaders.getHeaders(),"User-Agent"), "User-Agent header null.");
|
||||||
|
Assertions.assertEquals(expectedUserAgent, HTTPHeaderUtil.getSingleHeader(requestWithDefaultHeaders.getHeaders(),"User-Agent"),
|
||||||
|
"User-Agent header not populated with expected value \""+expectedUserAgent+"\".");
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue