Skip to content

Commit e1c1055

Browse files
authored
Merge pull request #2200 from microsoft/u/christiano/fix-redirect-handler
fix: Fixing redirect 301 handling
2 parents ec4730d + 3930f8b commit e1c1055

2 files changed

Lines changed: 149 additions & 2 deletions

File tree

‎components/http/okHttp/src/main/java/com/microsoft/kiota/http/middleware/RedirectHandler.java‎

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -129,9 +129,21 @@ Request getRedirect(
129129
.scrubSensitiveHeaders()
130130
.scrubHeaders(requestBuilder, requestUrl, proxyResolver);
131131

132-
// Response status code 303 See Other then POST changes to GET
133-
if (userResponse.code() == HTTP_SEE_OTHER) {
132+
final String method = request.method();
133+
final int responseCode = userResponse.code();
134+
final boolean redirectsToGet =
135+
((responseCode == HTTP_MOVED_PERM || responseCode == HTTP_MOVED_TEMP)
136+
&& "POST".equals(method))
137+
|| (responseCode == HTTP_SEE_OTHER
138+
&& !"GET".equals(method)
139+
&& !"HEAD".equals(method));
140+
if (redirectsToGet) {
134141
requestBuilder.method("GET", null);
142+
requestBuilder.removeHeader("Content-Length");
143+
requestBuilder.removeHeader("Transfer-Encoding");
144+
requestBuilder.removeHeader("Content-Type");
145+
requestBuilder.removeHeader("Content-Encoding");
146+
requestBuilder.removeHeader("Content-Language");
135147
}
136148

137149
return requestBuilder.build();

‎components/http/okHttp/src/test/java/com/microsoft/kiota/http/middleware/RedirectHandlerTests.java‎

Lines changed: 135 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
import static org.junit.Assert.assertNull;
44
import static org.junit.jupiter.api.Assertions.assertEquals;
55
import static org.junit.jupiter.api.Assertions.assertNotNull;
6+
import static org.junit.jupiter.api.Assertions.assertSame;
67
import static org.mockito.Mockito.*;
78

89
import com.microsoft.kiota.http.KiotaClientFactory;
@@ -14,12 +15,84 @@
1415
import okhttp3.mockwebserver.RecordedRequest;
1516

1617
import org.junit.jupiter.api.Test;
18+
import org.junit.jupiter.params.ParameterizedTest;
19+
import org.junit.jupiter.params.provider.ValueSource;
1720

1821
import java.net.*;
1922
import java.util.Collections;
2023

2124
@SuppressWarnings("resource")
2225
public class RedirectHandlerTests {
26+
private static final MediaType REQUEST_MEDIA_TYPE =
27+
MediaType.parse("application/json; charset=utf-8");
28+
private static final String REQUEST_BODY = "{\"value\":\"test\"}";
29+
30+
@ParameterizedTest
31+
@ValueSource(ints = {301, 302})
32+
void postRedirectsToGetWithoutBodyOrBodyHeaders(int statusCode) throws Exception {
33+
Request original = createRequest("POST");
34+
Response redirect =
35+
createRedirectResponse(original, statusCode, "http://other.example.com/redirected");
36+
37+
Request result =
38+
new RedirectHandler().getRedirect(original, redirect, new RedirectHandlerOption());
39+
40+
assertNotNull(result);
41+
assertEquals("GET", result.method());
42+
assertNull(result.body());
43+
assertBodyHeadersRemoved(result);
44+
assertCrossOriginHeadersRemoved(result);
45+
}
46+
47+
@Test
48+
void seeOtherRedirectsNonGetOrHeadToGetWithoutBodyOrBodyHeaders() throws Exception {
49+
Request original = createRequest("PUT");
50+
Response redirect =
51+
createRedirectResponse(original, 303, "http://other.example.com/redirected");
52+
53+
Request result =
54+
new RedirectHandler().getRedirect(original, redirect, new RedirectHandlerOption());
55+
56+
assertNotNull(result);
57+
assertEquals("GET", result.method());
58+
assertNull(result.body());
59+
assertBodyHeadersRemoved(result);
60+
assertCrossOriginHeadersRemoved(result);
61+
}
62+
63+
@ParameterizedTest
64+
@ValueSource(strings = {"GET", "HEAD"})
65+
void seeOtherPreservesGetAndHead(String method) throws Exception {
66+
Request original = createBodylessRequest(method);
67+
Response redirect =
68+
createRedirectResponse(original, 303, "http://other.example.com/redirected");
69+
70+
Request result =
71+
new RedirectHandler().getRedirect(original, redirect, new RedirectHandlerOption());
72+
73+
assertNotNull(result);
74+
assertEquals(method, result.method());
75+
assertNull(result.body());
76+
assertBodyHeadersPreserved(result);
77+
assertCrossOriginHeadersRemoved(result);
78+
}
79+
80+
@ParameterizedTest
81+
@ValueSource(ints = {307, 308})
82+
void redirectsPreserveMethodBodyAndBodyHeaders(int statusCode) throws Exception {
83+
Request original = createRequest("POST");
84+
Response redirect =
85+
createRedirectResponse(original, statusCode, "http://other.example.com/redirected");
86+
87+
Request result =
88+
new RedirectHandler().getRedirect(original, redirect, new RedirectHandlerOption());
89+
90+
assertNotNull(result);
91+
assertEquals("POST", result.method());
92+
assertSame(original.body(), result.body());
93+
assertBodyHeadersPreserved(result);
94+
assertCrossOriginHeadersRemoved(result);
95+
}
2396

2497
@Test
2598
void redirectsAreFollowedByDefault() throws Exception {
@@ -384,4 +457,66 @@ void customScrubberRemovesCustomHeaders() throws Exception {
384457
assertNull(result.header("X-Api-Key")); // stripped by custom scrubber
385458
assertNotNull(result.header("X-Safe-Header")); // kept (not in scrub list)
386459
}
460+
461+
private static Request createRequest(String method) {
462+
RequestBody body = RequestBody.create(REQUEST_BODY, REQUEST_MEDIA_TYPE);
463+
return new Request.Builder()
464+
.url("http://trusted.example.com/api")
465+
.method(method, body)
466+
.headers(createRequestHeaders())
467+
.build();
468+
}
469+
470+
private static Request createBodylessRequest(String method) {
471+
return new Request.Builder()
472+
.url("http://trusted.example.com/api")
473+
.method(method, null)
474+
.headers(createRequestHeaders())
475+
.build();
476+
}
477+
478+
private static Headers createRequestHeaders() {
479+
return new Headers.Builder()
480+
.set("Content-Length", String.valueOf(REQUEST_BODY.length()))
481+
.set("Transfer-Encoding", "chunked")
482+
.set("Content-Type", REQUEST_MEDIA_TYPE.toString())
483+
.set("Content-Encoding", "gzip")
484+
.set("Content-Language", "en-US")
485+
.set("Authorization", "Bearer secret")
486+
.set("Cookie", "session=SECRET")
487+
.build();
488+
}
489+
490+
private static Response createRedirectResponse(
491+
Request request, int statusCode, String location) {
492+
return new Response.Builder()
493+
.request(request)
494+
.protocol(Protocol.HTTP_1_1)
495+
.code(statusCode)
496+
.message("Redirect")
497+
.header("Location", location)
498+
.body(ResponseBody.create("", MediaType.parse("text/plain")))
499+
.build();
500+
}
501+
502+
private static void assertBodyHeadersRemoved(Request request) {
503+
assertNull(request.header("Content-Length"));
504+
assertNull(request.header("Transfer-Encoding"));
505+
assertNull(request.header("Content-Type"));
506+
assertNull(request.header("Content-Encoding"));
507+
assertNull(request.header("Content-Language"));
508+
}
509+
510+
private static void assertBodyHeadersPreserved(Request request) {
511+
assertEquals(String.valueOf(REQUEST_BODY.length()), request.header("Content-Length"));
512+
assertEquals("chunked", request.header("Transfer-Encoding"));
513+
assertEquals(REQUEST_MEDIA_TYPE.toString(), request.header("Content-Type"));
514+
assertEquals("gzip", request.header("Content-Encoding"));
515+
assertEquals("en-US", request.header("Content-Language"));
516+
}
517+
518+
private static void assertCrossOriginHeadersRemoved(Request request) {
519+
assertNull(request.header("Authorization"));
520+
assertNull(request.header("Cookie"));
521+
}
387522
}

0 commit comments

Comments
 (0)