-
Notifications
You must be signed in to change notification settings - Fork 228
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #1477 from microsoft/rsh/java-core-migration
initial middleware implementations
- Loading branch information
Showing
18 changed files
with
1,336 additions
and
6 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
63 changes: 63 additions & 0 deletions
63
http/java/okhttp/lib/src/main/java/com/microsoft/kiota/http/middleware/ChaosHandler.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,63 @@ | ||
package com.microsoft.kiota.http.middleware; | ||
|
||
import java.io.IOException; | ||
import java.util.concurrent.ThreadLocalRandom; | ||
|
||
import javax.annotation.Nonnull; | ||
|
||
import okhttp3.Interceptor; | ||
import okhttp3.MediaType; | ||
import okhttp3.Protocol; | ||
import okhttp3.Request; | ||
import okhttp3.Response; | ||
import okhttp3.ResponseBody; | ||
|
||
/** | ||
* DO NOT USE IN PRODUCTION | ||
* interceptor that randomly fails the responses for unit testing purposes | ||
*/ | ||
public class ChaosHandler implements Interceptor { | ||
/** | ||
* constant string being used | ||
*/ | ||
private static final String RETRY_AFTER = "Retry-After"; | ||
/** | ||
* Denominator for the failure rate (i.e. 1/X) | ||
*/ | ||
private static final int failureRate = 3; | ||
/** | ||
* default value to return on retry after | ||
*/ | ||
private static final String retryAfterValue = "10"; | ||
/** | ||
* body to respond on failed requests | ||
*/ | ||
private static final String responseBody = "{\"error\": {\"code\": \"TooManyRequests\",\"innerError\": {\"code\": \"429\",\"date\": \"2020-08-18T12:51:51\",\"message\": \"Please retry after\",\"request-id\": \"94fb3b52-452a-4535-a601-69e0a90e3aa2\",\"status\": \"429\"},\"message\": \"Please retry again later.\"}}"; | ||
/** | ||
* Too many requests status code | ||
*/ | ||
public static final int MSClientErrorCodeTooManyRequests = 429; | ||
|
||
@Override | ||
@Nonnull | ||
public Response intercept(@Nonnull final Chain chain) throws IOException { | ||
Request request = chain.request(); | ||
|
||
final int dice = ThreadLocalRandom.current().nextInt(1, Integer.MAX_VALUE); | ||
|
||
if(dice % failureRate == 0) { | ||
return new Response | ||
.Builder() | ||
.request(request) | ||
.protocol(Protocol.HTTP_1_1) | ||
.code(MSClientErrorCodeTooManyRequests) | ||
.message("Too Many Requests") | ||
.addHeader(RETRY_AFTER, retryAfterValue) | ||
.body(ResponseBody.create(responseBody, MediaType.get("application/json"))) | ||
.build(); | ||
} else { | ||
return chain.proceed(request); | ||
} | ||
} | ||
|
||
} |
136 changes: 136 additions & 0 deletions
136
http/java/okhttp/lib/src/main/java/com/microsoft/kiota/http/middleware/RedirectHandler.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,136 @@ | ||
package com.microsoft.kiota.http.middleware; | ||
|
||
import static java.net.HttpURLConnection.HTTP_MOVED_PERM; | ||
import static java.net.HttpURLConnection.HTTP_MOVED_TEMP; | ||
import static java.net.HttpURLConnection.HTTP_SEE_OTHER; | ||
import static okhttp3.internal.http.StatusLine.HTTP_PERM_REDIRECT; | ||
import static okhttp3.internal.http.StatusLine.HTTP_TEMP_REDIRECT; | ||
|
||
import java.io.IOException; | ||
import java.net.ProtocolException; | ||
|
||
import javax.annotation.Nullable; | ||
import javax.annotation.Nonnull; | ||
|
||
import com.microsoft.kiota.http.middleware.options.RedirectHandlerOption; | ||
|
||
import okhttp3.HttpUrl; | ||
import okhttp3.Interceptor; | ||
import okhttp3.Request; | ||
import okhttp3.Response; | ||
|
||
/** | ||
* Middleware that determines whether a redirect information should be followed or not, and follows it if necessary. | ||
*/ | ||
public class RedirectHandler implements Interceptor{ | ||
|
||
private RedirectHandlerOption mRedirectOption; | ||
|
||
/** | ||
* Initialize using default redirect options, default IShouldRedirect and max redirect value | ||
*/ | ||
public RedirectHandler() { | ||
this(null); | ||
} | ||
|
||
/** | ||
* Initialize using custom redirect options. | ||
* @param redirectOption pass instance of redirect options to be used | ||
*/ | ||
public RedirectHandler(@Nullable final RedirectHandlerOption redirectOption) { | ||
this.mRedirectOption = redirectOption; | ||
if(redirectOption == null) { | ||
this.mRedirectOption = new RedirectHandlerOption(); | ||
} | ||
} | ||
|
||
boolean isRedirected(Request request, Response response, int redirectCount, RedirectHandlerOption redirectOption) throws IOException { | ||
// Check max count of redirects reached | ||
if(redirectCount > redirectOption.maxRedirects()) return false; | ||
|
||
// Location header empty then don't redirect | ||
final String locationHeader = response.header("location"); | ||
if(locationHeader == null) | ||
return false; | ||
|
||
// If any of 301,302,303,307,308 then redirect | ||
final int statusCode = response.code(); | ||
if(statusCode == HTTP_PERM_REDIRECT || //308 | ||
statusCode == HTTP_MOVED_PERM || //301 | ||
statusCode == HTTP_TEMP_REDIRECT || //307 | ||
statusCode == HTTP_SEE_OTHER || //303 | ||
statusCode == HTTP_MOVED_TEMP) //302 | ||
return true; | ||
|
||
return false; | ||
} | ||
|
||
Request getRedirect( | ||
final Request request, | ||
final Response userResponse) throws ProtocolException { | ||
String location = userResponse.header("Location"); | ||
if (location == null || location.length() == 0) return null; | ||
|
||
// For relative URL in location header, the new url to redirect is relative to original request | ||
if(location.startsWith("/")) { | ||
if(request.url().toString().endsWith("/")) { | ||
location = location.substring(1); | ||
} | ||
location = request.url() + location; | ||
} | ||
|
||
HttpUrl requestUrl = userResponse.request().url(); | ||
|
||
HttpUrl locationUrl = userResponse.request().url().resolve(location); | ||
|
||
// Don't follow redirects to unsupported protocols. | ||
if (locationUrl == null) return null; | ||
|
||
// Most redirects don't include a request body. | ||
Request.Builder requestBuilder = userResponse.request().newBuilder(); | ||
|
||
// When redirecting across hosts, drop all authentication headers. This | ||
// is potentially annoying to the application layer since they have no | ||
// way to retain them. | ||
boolean sameScheme = locationUrl.scheme().equalsIgnoreCase(requestUrl.scheme()); | ||
boolean sameHost = locationUrl.host().toString().equalsIgnoreCase(requestUrl.host().toString()); | ||
if (!sameScheme || !sameHost) { | ||
requestBuilder.removeHeader("Authorization"); | ||
} | ||
|
||
// Response status code 303 See Other then POST changes to GET | ||
if(userResponse.code() == HTTP_SEE_OTHER) { | ||
requestBuilder.method("GET", null); | ||
} | ||
|
||
return requestBuilder.url(locationUrl).build(); | ||
} | ||
|
||
// Intercept request and response made to network | ||
@Override | ||
@Nonnull | ||
public Response intercept(@Nonnull final Chain chain) throws IOException { | ||
Request request = chain.request(); | ||
Response response = null; | ||
int requestsCount = 1; | ||
|
||
// Use should retry pass along with this request | ||
RedirectHandlerOption redirectOption = request.tag(RedirectHandlerOption.class); | ||
redirectOption = redirectOption != null ? redirectOption : this.mRedirectOption; | ||
|
||
while(true) { | ||
response = chain.proceed(request); | ||
final boolean shouldRedirect = isRedirected(request, response, requestsCount, redirectOption) | ||
&& redirectOption.shouldRedirect().shouldRedirect(response); | ||
if(!shouldRedirect) break; | ||
|
||
final Request followup = getRedirect(request, response); | ||
if(followup != null) { | ||
response.close(); | ||
request = followup; | ||
requestsCount++; | ||
} | ||
} | ||
return response; | ||
} | ||
} |
Oops, something went wrong.