make UrlResolver reuse commons Http redirectory strategy
authorEugene Petrenko <eugene.petrenko@gmail.com>
Fri, 12 Aug 2011 12:56:56 +0000 (16:56 +0400)
committerEugene Petrenko <eugene.petrenko@gmail.com>
Fri, 12 Aug 2011 12:56:56 +0000 (16:56 +0400)
nuget-server/src/jetbrains/buildServer/nuget/server/feed/reader/impl/FeedClient.java
nuget-server/src/jetbrains/buildServer/nuget/server/feed/reader/impl/UrlResolverImpl.java
nuget-tests/src/jetbrains/buildServer/nuget/tests/server/feed/reader/UrlResolverTest.java [new file with mode: 0644]

index 22a904b9703ced77391426f9f46554a6f3b8df2b..aa8f0f486ae27976748f669a346785331ebeb14c 100644 (file)
@@ -17,7 +17,6 @@
 package jetbrains.buildServer.nuget.server.feed.reader.impl;\r
 \r
 import org.apache.http.HttpResponse;\r
 package jetbrains.buildServer.nuget.server.feed.reader.impl;\r
 \r
 import org.apache.http.HttpResponse;\r
-import org.apache.http.client.HttpClient;\r
 import org.apache.http.client.methods.HttpUriRequest;\r
 import org.jetbrains.annotations.NotNull;\r
 \r
 import org.apache.http.client.methods.HttpUriRequest;\r
 import org.jetbrains.annotations.NotNull;\r
 \r
index 4a583ab6191c9aa6a3dd6e2d07f83b47300ac341..256113c41ca0c25ec1a166c9c5a0a620af5956ec 100644 (file)
 \r
 package jetbrains.buildServer.nuget.server.feed.reader.impl;\r
 \r
 \r
 package jetbrains.buildServer.nuget.server.feed.reader.impl;\r
 \r
+import com.intellij.openapi.diagnostic.Logger;\r
 import com.intellij.openapi.util.Pair;\r
 import com.intellij.openapi.util.Pair;\r
-import org.apache.http.Header;\r
 import org.apache.http.HttpResponse;\r
 import org.apache.http.HttpStatus;\r
 import org.apache.http.HttpResponse;\r
 import org.apache.http.HttpStatus;\r
+import org.apache.http.ProtocolException;\r
+import org.apache.http.client.RedirectStrategy;\r
 import org.apache.http.client.methods.HttpGet;\r
 import org.apache.http.client.methods.HttpGet;\r
+import org.apache.http.client.methods.HttpUriRequest;\r
 import org.apache.http.client.params.ClientPNames;\r
 import org.apache.http.client.params.ClientPNames;\r
+import org.apache.http.impl.client.DefaultRedirectStrategy;\r
+import org.apache.http.protocol.BasicHttpContext;\r
+import org.apache.http.protocol.HttpContext;\r
 import org.jetbrains.annotations.NotNull;\r
 import org.jetbrains.annotations.NotNull;\r
+import org.jetbrains.annotations.Nullable;\r
 \r
 import java.io.IOException;\r
 \r
 \r
 import java.io.IOException;\r
 \r
@@ -31,6 +38,8 @@ import java.io.IOException;
  * Date: 12.08.11 10:24\r
  */\r
 public class UrlResolverImpl implements UrlResolver {\r
  * Date: 12.08.11 10:24\r
  */\r
 public class UrlResolverImpl implements UrlResolver {\r
+  private static final Logger LOG = Logger.getInstance(UrlResolverImpl.class.getName());\r
+\r
   private final FeedClient myClient;\r
   private final FeedGetMethodFactory myMethods;\r
 \r
   private final FeedClient myClient;\r
   private final FeedGetMethodFactory myMethods;\r
 \r
@@ -56,15 +65,15 @@ public class UrlResolverImpl implements UrlResolver {
       ping.getParams().setBooleanParameter(ClientPNames.HANDLE_REDIRECTS, false);\r
 \r
       final HttpResponse execute = myClient.execute(ping);\r
       ping.getParams().setBooleanParameter(ClientPNames.HANDLE_REDIRECTS, false);\r
 \r
       final HttpResponse execute = myClient.execute(ping);\r
-      final int statusCode = execute.getStatusLine().getStatusCode();\r
-      if (statusCode / 100 == 3) {\r
-        final Header location = execute.getFirstHeader("Location");\r
-        if (location != null) {\r
-          feedUrl = location.getValue();\r
-          continue;\r
-        }\r
+\r
+      String redirected = getRedirectedUrl(ping, execute);\r
+      if (redirected != null) {\r
+        LOG.debug("Redirected to " + redirected);\r
+        feedUrl = redirected;\r
+        continue;\r
       }\r
 \r
       }\r
 \r
+      final int statusCode = execute.getStatusLine().getStatusCode();\r
       if (statusCode != HttpStatus.SC_OK) {\r
         throw new IOException("Failed to connect to " + feedUrl);\r
       }\r
       if (statusCode != HttpStatus.SC_OK) {\r
         throw new IOException("Failed to connect to " + feedUrl);\r
       }\r
@@ -73,4 +82,27 @@ public class UrlResolverImpl implements UrlResolver {
     throw new IOException("Failed to resolve redirects");\r
   }\r
 \r
     throw new IOException("Failed to resolve redirects");\r
   }\r
 \r
+  private HttpContext createContext() {\r
+    return new BasicHttpContext();\r
+  }\r
+\r
+  @NotNull\r
+  public RedirectStrategy getRedirectStrategy() {\r
+    //TODO: could use http client for that\r
+    return new DefaultRedirectStrategy();\r
+  }\r
+\r
+  @Nullable\r
+  public String getRedirectedUrl(@NotNull HttpUriRequest request, @NotNull HttpResponse response) throws IOException {\r
+    try {\r
+      final RedirectStrategy redirectStrategy = getRedirectStrategy();\r
+      if (!redirectStrategy.isRedirected(request,response, createContext())) {\r
+        return null;\r
+      }\r
+\r
+      return redirectStrategy.getRedirect(request, response, createContext()).getURI().toString();\r
+    } catch (ProtocolException e) {\r
+      return null;\r
+    }\r
+  }\r
 }\r
 }\r
diff --git a/nuget-tests/src/jetbrains/buildServer/nuget/tests/server/feed/reader/UrlResolverTest.java b/nuget-tests/src/jetbrains/buildServer/nuget/tests/server/feed/reader/UrlResolverTest.java
new file mode 100644 (file)
index 0000000..64f605d
--- /dev/null
@@ -0,0 +1,190 @@
+/*\r
+ * Copyright 2000-2011 JetBrains s.r.o.\r
+ *\r
+ * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * you may not use this file except in compliance with the License.\r
+ * You may obtain a copy of the License at\r
+ *\r
+ * http://www.apache.org/licenses/LICENSE-2.0\r
+ *\r
+ * Unless required by applicable law or agreed to in writing, software\r
+ * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * See the License for the specific language governing permissions and\r
+ * limitations under the License.\r
+ */\r
+\r
+package jetbrains.buildServer.nuget.tests.server.feed.reader;\r
+\r
+import com.intellij.openapi.util.Pair;\r
+import jetbrains.buildServer.BaseTestCase;\r
+import jetbrains.buildServer.nuget.server.feed.reader.impl.FeedClient;\r
+import jetbrains.buildServer.nuget.server.feed.reader.impl.FeedGetMethodFactory;\r
+import jetbrains.buildServer.nuget.server.feed.reader.impl.UrlResolver;\r
+import jetbrains.buildServer.nuget.server.feed.reader.impl.UrlResolverImpl;\r
+import org.apache.http.HttpResponse;\r
+import org.apache.http.HttpStatus;\r
+import org.apache.http.HttpVersion;\r
+import org.apache.http.client.methods.HttpUriRequest;\r
+import org.apache.http.message.BasicHttpResponse;\r
+import org.hamcrest.BaseMatcher;\r
+import org.hamcrest.Description;\r
+import org.jetbrains.annotations.NotNull;\r
+import org.jmock.Expectations;\r
+import org.jmock.Mockery;\r
+import org.testng.Assert;\r
+import org.testng.annotations.BeforeMethod;\r
+import org.testng.annotations.Test;\r
+\r
+import java.io.IOException;\r
+\r
+/**\r
+ * Created by Eugene Petrenko (eugene.petrenko@gmail.com)\r
+ * Date: 12.08.11 15:26\r
+ */\r
+public class UrlResolverTest extends BaseTestCase {\r
+  private Mockery m;\r
+  private FeedClient myFeedClient;\r
+  private UrlResolver myResolver;\r
+\r
+  @BeforeMethod\r
+  @Override\r
+  protected void setUp() throws Exception {\r
+    super.setUp();\r
+    m = new Mockery();\r
+    myFeedClient = m.mock(FeedClient.class);\r
+    myResolver = new UrlResolverImpl(myFeedClient, new FeedGetMethodFactory());\r
+  }\r
+\r
+  @Test\r
+  public void test_should_support_200() throws IOException {\r
+    m.checking(new Expectations() {{\r
+      oneOf(myFeedClient).execute(with(httpGet("http://www.jetbrains.com")));\r
+      will(returnValue(responseStatus(200)));\r
+    }});\r
+\r
+    final Pair<String, HttpResponse> pair = myResolver.resolvePath("http://www.jetbrains.com");\r
+    Assert.assertEquals(pair.first, "http://www.jetbrains.com");\r
+  }\r
+\r
+  @Test\r
+  public void test_should_support_3xx() throws IOException {\r
+    m.checking(new Expectations() {{\r
+      oneOf(myFeedClient).execute(with(httpGet("http://www.jetbrains.com")));\r
+      will(returnValue(responseLocationStatus(HttpStatus.SC_MOVED_PERMANENTLY, "http://www.google.com")));\r
+      oneOf(myFeedClient).execute(with(httpGet("http://www.google.com")));\r
+      will(returnValue(responseStatus(200)));\r
+    }});\r
+\r
+    final Pair<String, HttpResponse> pair = myResolver.resolvePath("http://www.jetbrains.com");\r
+    Assert.assertEquals(pair.first, "http://www.google.com");\r
+  }\r
+\r
+  @Test\r
+  public void test_should_support_3xx_ms() throws IOException {\r
+    m.checking(new Expectations() {{\r
+      oneOf(myFeedClient).execute(with(httpGet("http://www.jetbrains.com/redirect?fwLink=555")));\r
+      will(returnValue(responseLocationStatus(HttpStatus.SC_MOVED_PERMANENTLY, "http://www.google.com")));\r
+      oneOf(myFeedClient).execute(with(httpGet("http://www.google.com")));\r
+      will(returnValue(responseStatus(200)));\r
+    }});\r
+\r
+    final Pair<String, HttpResponse> pair = myResolver.resolvePath("http://www.jetbrains.com/redirect?fwLink=555");\r
+    Assert.assertEquals(pair.first, "http://www.google.com");\r
+  }\r
+\r
+  @Test\r
+  public void test_should_support_3xx_multi() throws IOException {\r
+    m.checking(new Expectations() {{\r
+      oneOf(myFeedClient).execute(with(httpGet("http://www.jetbrains.com")));\r
+      will(returnValue(responseLocationStatus(HttpStatus.SC_MOVED_PERMANENTLY, "http://domain_1.jonnyzzz.com")));\r
+\r
+      oneOf(myFeedClient).execute(with(httpGet("http://domain_1.jonnyzzz.com")));\r
+      will(returnValue(responseLocationStatus(HttpStatus.SC_MOVED_TEMPORARILY, "http://domain_2.jonnyzzz.com")));\r
+\r
+      oneOf(myFeedClient).execute(with(httpGet("http://domain_2.jonnyzzz.com")));\r
+      will(returnValue(responseLocationStatus(HttpStatus.SC_TEMPORARY_REDIRECT, "http://domain_3.jonnyzzz.com")));\r
+\r
+      oneOf(myFeedClient).execute(with(httpGet("http://domain_3.jonnyzzz.com")));\r
+      will(returnValue(responseLocationStatus(HttpStatus.SC_MOVED_PERMANENTLY, "http://domain_4.jonnyzzz.com")));\r
+\r
+      oneOf(myFeedClient).execute(with(httpGet("http://domain_4.jonnyzzz.com")));\r
+      will(returnValue(responseLocationStatus(HttpStatus.SC_MOVED_PERMANENTLY, "http://www.google.com")));\r
+\r
+      oneOf(myFeedClient).execute(with(httpGet("http://www.google.com")));\r
+      will(returnValue(responseStatus(200)));\r
+    }});\r
+\r
+    final Pair<String, HttpResponse> pair = myResolver.resolvePath("http://www.jetbrains.com");\r
+    Assert.assertEquals(pair.first, "http://www.google.com");\r
+  }\r
+\r
+  @Test\r
+  public void test_should_support_3xx_loop() throws IOException {\r
+    m.checking(new Expectations() {{\r
+      allowing(myFeedClient).execute(with(httpGet("http://www.jetbrains.com")));\r
+      will(returnValue(responseLocationStatus(HttpStatus.SC_MOVED_PERMANENTLY, "http://www.jetbrains.com")));\r
+    }});\r
+\r
+    try {\r
+      myResolver.resolvePath("http://www.jetbrains.com");\r
+    } catch (IOException e) {\r
+      return;\r
+    }\r
+    Assert.fail();\r
+  }\r
+\r
+  @Test\r
+  public void test_should_fail_on_500() throws IOException {\r
+    m.checking(new Expectations() {{\r
+      oneOf(myFeedClient).execute(with(httpGet("http://www.jetbrains.com")));\r
+      will(returnValue(responseStatus(500)));\r
+    }});\r
+\r
+    try {\r
+      myResolver.resolvePath("http://www.jetbrains.com");\r
+    } catch (IOException e) {\r
+      return;\r
+    }\r
+    Assert.fail();\r
+  }\r
+\r
+  @Test\r
+  public void test_should_fail_on_400() throws IOException {\r
+    m.checking(new Expectations() {{\r
+      oneOf(myFeedClient).execute(with(httpGet("http://www.jetbrains.com")));\r
+      will(returnValue(responseStatus(400)));\r
+    }});\r
+\r
+    try {\r
+      myResolver.resolvePath("http://www.jetbrains.com");\r
+    } catch (IOException e) {\r
+      return;\r
+    }\r
+    Assert.fail();\r
+  }\r
+\r
+  private static HttpResponse responseStatus(int status) {\r
+    return new BasicHttpResponse(HttpVersion.HTTP_1_0, status, "Status: " + status);\r
+  }\r
+\r
+  private static HttpResponse responseLocationStatus(int status, @NotNull String location) {\r
+    final BasicHttpResponse res = new BasicHttpResponse(HttpVersion.HTTP_1_0, status, "Status: " + status);\r
+    res.addHeader("Location", location);\r
+    return res;\r
+  }\r
+\r
+  private static BaseMatcher<HttpUriRequest> httpGet(@NotNull final String url) {\r
+    return new BaseMatcher<HttpUriRequest>() {\r
+      public boolean matches(Object o) {\r
+        if (!(o instanceof org.apache.http.client.methods.HttpGet)) return false;\r
+        org.apache.http.client.methods.HttpGet get = (org.apache.http.client.methods.HttpGet) o;\r
+        return get.getURI().toString().equals(url);\r
+      }\r
+\r
+      public void describeTo(Description description) {\r
+        description.appendText("HttpGet to ").appendText(url);\r
+      }\r
+    };\r
+  }\r
+}\r