Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Rsh/url replace handler #494

Merged
merged 8 commits into from
Jul 20, 2023
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

### Added

- Adds the `UrlReplaceHandler` middleware to the Okhttp component to allow for customizing the URL before sending the request.

## [0.4.6] - 2023-07-20

### Added
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
package com.microsoft.kiota.http.middleware;

import com.microsoft.kiota.http.middleware.options.UrlReplaceHandlerOption;
import io.opentelemetry.api.trace.Span;
import io.opentelemetry.context.Scope;
import okhttp3.Interceptor;
import okhttp3.Request;
import okhttp3.Response;

import javax.annotation.Nonnull;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.util.Map;
import java.util.Objects;

/**
* A middleware to replace the url with the specified replacement pairs.
*/
public class UrlReplaceHandler implements Interceptor {

private UrlReplaceHandlerOption mUrlReplaceHandlerOption;

/**
* Instantiate a GraphTelemetryHandler with default GraphClientOption.
*/
public UrlReplaceHandler(){
this(new UrlReplaceHandlerOption());
}
/**
* Instantiate a GraphTelemetryHandler with specified GraphClientOption
ramsessanchez marked this conversation as resolved.
Show resolved Hide resolved
* @param urlReplaceHandlerOption the specified GraphClientOption for the GraphTelemetryHandler.
*/
public UrlReplaceHandler(@Nonnull UrlReplaceHandlerOption urlReplaceHandlerOption){
Objects.requireNonNull(urlReplaceHandlerOption);
this.mUrlReplaceHandlerOption = new UrlReplaceHandlerOption(urlReplaceHandlerOption.getReplacementPairs(), urlReplaceHandlerOption.isEnabled());
}
/** {@inheritDoc} */
@Nonnull
@Override
public Response intercept(@Nonnull Chain chain) throws IOException {
Objects.requireNonNull(chain, "parameter chain cannot be null");
Request request = Objects.requireNonNull(chain.request(), "request cannot be null");
UrlReplaceHandlerOption replaceOption = request.tag(UrlReplaceHandlerOption.class);
replaceOption = replaceOption == null ? mUrlReplaceHandlerOption : replaceOption;
if(!replaceOption.isEnabled() || replaceOption.getReplacementPairs().isEmpty()) {
return chain.proceed(request);
}

final Span span = ObservabilityHelper.getSpanForRequest(request, "UrlReplaceHandler_Intercept");
Scope scope = null;
if (span != null) {
scope = span.makeCurrent();
span.setAttribute("com.microsoft.kiota.handler.urlreplace.enable", true);
}
try{
request = replaceRequestUrl(request, replaceOption.getReplacementPairs());
} finally {
if (scope != null) {
scope.close();
}
if (span != null) {
span.end();
}
}
return chain.proceed(request);
}
/**
* Gets the GraphClientOption for the GraphTelemetryHandler.
* @return the GraphClientOption for the GraphTelemetryHandler.
*/
ramsessanchez marked this conversation as resolved.
Show resolved Hide resolved
public UrlReplaceHandlerOption getUrlReplaceHandlerOption() {
return new UrlReplaceHandlerOption(mUrlReplaceHandlerOption.getReplacementPairs(), mUrlReplaceHandlerOption.isEnabled());
}
/**
* Sets the GraphClientOption for the GraphTelemetryHandler.
* @param urlReplaceHandlerOption the GraphClientOption to set.
*/
public void setUrlReplaceHandlerOption(UrlReplaceHandlerOption urlReplaceHandlerOption) {
this.mUrlReplaceHandlerOption = new UrlReplaceHandlerOption(urlReplaceHandlerOption.getReplacementPairs(), urlReplaceHandlerOption.isEnabled());
}
/**
* Replaces the url of the request using the replacement pairs provided.
* @param request the request to replace the url of.
* @param replacementPairs the replacement pairs to use.
* @return the request with the updated url.
* @throws UnsupportedEncodingException if the url encoding is not supported.
*/
@Nonnull
public static Request replaceRequestUrl(@Nonnull Request request, @Nonnull Map<String, String> replacementPairs) throws UnsupportedEncodingException {
Request.Builder builder = request.newBuilder();
//Decoding the url since Request.url is encoded by default.
String replacedUrl = URLDecoder.decode(request.url().toString(), "UTF-8");//Using decode(String,String) method to maintain source compatibility with Java 8
for (Map.Entry<String, String> entry : replacementPairs.entrySet()) {
replacedUrl = replacedUrl.replace(entry.getKey(), entry.getValue());
}
builder.url(replacedUrl);
return builder.build();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
package com.microsoft.kiota.http.middleware.options;

import com.microsoft.kiota.RequestOption;

import javax.annotation.Nonnull;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;

/**
* The options to be passed to the UrlReplaceHandler.
* Defines the replacement pairs and whether the handler is enabled or not.
*/
public class UrlReplaceHandlerOption implements RequestOption {

private Map<String, String> replacementPairs;
private boolean enabled;

/**
* Instantiates a new UrlReplaceOption with an empty replacementPairs map and enabled set to true.
*/
public UrlReplaceHandlerOption() {
this(new HashMap<>());
}
/**
* Instantiates a new UrlReplaceOption with the specified replacementPairs map and enabled set to true.
* @param replacementPairs the replacement pairs map.
*/
public UrlReplaceHandlerOption(@Nonnull Map<String, String> replacementPairs) {
this(replacementPairs, true);
}
/**
* Instantiates a new UrlReplaceOption with the specified replacementPairs map and enabled set to the specified value.
* @param enabled whether the handler is enabled or not.
* @param replacementPairs the replacement pairs map.
*/
public UrlReplaceHandlerOption(@Nonnull Map<String, String> replacementPairs, boolean enabled) {
Objects.requireNonNull(replacementPairs);
this.replacementPairs = new HashMap<>(replacementPairs);
this.enabled = enabled;
}
/**
* Gets the replacement pairs map.
* @return the replacement pairs map.
*/
public Map<String, String> getReplacementPairs() {
return new HashMap<>(replacementPairs);
}
/**
* Sets the replacement pairs map.
* @param replacementPairs the replacement pairs map.
*/
public void setReplacementPairs(@Nonnull final Map<String, String> replacementPairs) {
this.replacementPairs = new HashMap<>(replacementPairs);
}
/**
* Enables the handler.
*/
public void enable() {
this.enabled = true;
}
/**
* Disables the handler.
*/
public void disable() {
this.enabled = false;
}
/**
* Gets whether the handler is enabled or not.
* @return whether the handler is enabled or not.
*/
public boolean isEnabled() {
return enabled;
}
@Nonnull
@SuppressWarnings("unchecked")
@Override
public <T extends RequestOption> Class<T> getType() {
return (Class<T>) UrlReplaceHandlerOption.class;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
package com.microsoft.kiota.http;

import com.microsoft.kiota.http.middleware.UrlReplaceHandler;
import com.microsoft.kiota.http.middleware.options.UrlReplaceHandlerOption;
import okhttp3.Interceptor;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;
import org.junit.jupiter.api.Test;

import java.io.IOException;
import java.util.HashMap;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull;

class UrlReplaceHandlerTest {

private final static String defaultUsersWithTokenUrl = "https://graph.microsoft.com/v1.0/users/TokenToReplace";
private final static HashMap<String, String> defaultReplacementPairs = new HashMap<>();

@Test
void testUrlReplaceHandler_no_replacementPairs() throws IOException {
Interceptor[] interceptors = new Interceptor[]{new UrlReplaceHandler(new UrlReplaceHandlerOption())};
final OkHttpClient client = KiotaClientFactory.create(interceptors).build();
final Request request = new Request.Builder().url(defaultUsersWithTokenUrl).build();
final Response response = client.newCall(request).execute();

assertNotNull(response);
assertEquals(defaultUsersWithTokenUrl, response.request().url().toString()); //url should remain the same without replacement pairs

}
@Test
void testUrlReplaceHandler_default_url() throws IOException {
defaultReplacementPairs.put("/users/TokenToReplace", "/me");
Interceptor[] interceptors = new Interceptor[]{new UrlReplaceHandler(new UrlReplaceHandlerOption(defaultReplacementPairs))};
final OkHttpClient client = KiotaClientFactory.create(interceptors).build();
final Request request = new Request.Builder().url(defaultUsersWithTokenUrl).build();
final Response response = client.newCall(request).execute();
final String expectedNewUrl = "https://graph.microsoft.com/v1.0/me";

assertNotNull(response);
assertEquals(expectedNewUrl, response.request().url().toString());
}
@Test
void testUrlReplaceHandler_multiple_pairs() throws IOException {
defaultReplacementPairs.put("/users/TokenToReplace", "/me");
defaultReplacementPairs.put("{secondToken}", "expectedValue");
String customUrl = "https://graph.microsoft.com/beta/users/TokenToReplace/{secondToken}"; //using special characters to test decoding.
Interceptor[] interceptors = new Interceptor[]{new UrlReplaceHandler(new UrlReplaceHandlerOption(defaultReplacementPairs))};
final OkHttpClient client = KiotaClientFactory.create(interceptors).build();
final Request request = new Request.Builder().url(customUrl).build();
final Response response = client.newCall(request).execute();
final String expectedNewUrl = "https://graph.microsoft.com/beta/me/expectedValue";

assertNotNull(response);
assertEquals(expectedNewUrl, response.request().url().toString());
}
}
Loading