Why do it?

LuciadCPillar allows you to connect to access-restricted web services by providing authentication credentials.

There are cases where web services require forms of authentication that LuciadCPillar doesn’t support internally, such as bearer token schemes or signed URLs. In these cases, you can control HTTP requests to get access-restricted resources, either by adding HTTP headers and URI query parameters, or by modifying requests based on server responses.

How to do it?

You customize HTTP data loading by creating an IHttpClientIHttpClientIHttpClient and passing it to model decoders that implement HTTP data loading.

For cases where you simply want to add HTTP headers and URI query parameters to each request, the LuciadCPillar API provides the HttpClientHttpClientHttpClient class. That’s a ready-made implementation of the IHttpClientIHttpClientIHttpClient interface, which you can use to add HttpRequestOptionsHttpRequestOptionsHttpRequestOptions to HTTP requests.

Program: HttpClient usage shows an example of how you can use the HTTP client.

Program: HttpClient usage
auto httpClient = HttpClient::newBuilder().build();

auto httpRequestOptions = HttpRequestOptions::newBuilder().header("Authorization", "Bearer FooToken").build();
httpClient->setHttpRequestOptions(httpRequestOptions);

auto options = Ogc3DTilesModelDecoder::Options::newBuilder().httpClient(httpClient).build();
auto model = Ogc3DTilesModelDecoder::decode(url, options);
var httpClient = HttpClient.NewBuilder().Build();

var httpRequestOptions = HttpRequestOptions.NewBuilder().Header("Authorization", "Bearer FooToken").Build();
httpClient.HttpRequestOptions = httpRequestOptions;

var options = Ogc3DTilesModelDecoder.Options.NewBuilder().HttpClient(httpClient).Build();
var model = Ogc3DTilesModelDecoder.Decode(url, options);
var httpClient = HttpClient.newBuilder().build();

var httpRequestOptions = HttpRequestOptions.newBuilder().header("Authorization", "Bearer FooToken").build();
httpClient.setHttpRequestOptions(httpRequestOptions);

var options = Ogc3DTilesModelDecoder.Options.newBuilder().httpClient(httpClient).build();
var model = Ogc3DTilesModelDecoder.decode(url, options);

If you require finer control over the sent requests to adapt them to your needs, or if you want to use your own HTTP connection implementation, you can create a custom IHttpClientIHttpClientIHttpClient.

Program: Custom HTTP data loading shows an example of a custom HTTP client that adapts the HTTP request by adding an authorization header.

Program: Custom HTTP data loading
class CustomHttpClient final : public IHttpClient {
public:
  explicit CustomHttpClient(std::string bearerToken) : _bearerToken(std::move(bearerToken)), _httpClient(HttpClient::newBuilder().build()) {
  }

  luciad::expected<HttpResponse, ErrorInfo> send(const HttpRequest& request, const CancellationToken& token) override {
    auto httpRequest = request.asBuilder().header("Authorization", "Bearer " + _bearerToken).build();

    auto response = _httpClient->send(httpRequest, token);

    if (response.has_value()) {
      std::cout << "Status code: " << response->getStatusCode() << std::endl;
    }

    return response;
  }

private:
  std::string _bearerToken;
  std::shared_ptr<HttpClient> _httpClient;
};
public class CustomHttpClient : IHttpClient
{
    private string _bearerToken;
    private HttpClient _httpClient;

    public CustomHttpClient(string bearerToken)
    {
        _bearerToken = bearerToken;
        _httpClient = HttpClient.NewBuilder().Build();
    }

    public HttpResponse Send(HttpRequest request, CancellationToken token)
    {
        var httpRequest = request.AsBuilder().Header("Authorization", "Bearer " + _bearerToken).Build();

        var response = _httpClient.Send(httpRequest, token);

        Console.WriteLine("Status code: " + response.StatusCode);

        return response;
    }
}
private static class CustomHttpClient implements IHttpClient {

  private final String _bearerToken;
  private final HttpClient _httpClient;

  CustomHttpClient(String bearerToken) {
    _bearerToken = bearerToken;
    _httpClient = HttpClient.newBuilder().build();
  }

  @Override
  public @NotNull HttpResponse send(@NotNull HttpRequest request, @NotNull CancellationToken token) throws IOException {
    var httpRequest = request.asBuilder().header("Authorization", "Bearer " + _bearerToken).build();

    var response = _httpClient.send(httpRequest, token);

    System.out.println("Status code: " + response.getStatusCode());

    return response;
  }
}

Program: Custom http client usage shows an example of how to use the custom HTTP client.

Program: Custom http client usage
auto customHttpClient = std::make_shared<CustomHttpClient>("FooToken");
auto options = Ogc3DTilesModelDecoder::Options::newBuilder().httpClient(customHttpClient).build();
auto model = Ogc3DTilesModelDecoder::decode(url, options);
var customHttpClient = new CustomHttpClient("FooToken");
var options = Ogc3DTilesModelDecoder.Options.NewBuilder()
                                            .HttpClient(customHttpClient)
                                            .Build();
var model = Ogc3DTilesModelDecoder.Decode(path, options);
var customHttpClient = new CustomHttpClient("FooToken");
var options = Ogc3DTilesModelDecoder.Options.newBuilder()
                                            .httpClient(customHttpClient)
                                            .build();
var model = Ogc3DTilesModelDecoder.decode(url, options);