mirror of https://github.com/apache/jclouds.git
Issue 76: parse response header Location
git-svn-id: http://jclouds.googlecode.com/svn/trunk@1985 3d8758e0-26b5-11de-8745-db77d3ebf521
This commit is contained in:
parent
eefd7d47f8
commit
ff9abb6884
|
@ -86,6 +86,11 @@ public class HttpUtils {
|
|||
}
|
||||
|
||||
private static String hmacBase64(String toEncode, byte[] key, Digest digest) {
|
||||
byte[] resBuf = hmac(toEncode, key, digest);
|
||||
return toBase64String(resBuf);
|
||||
}
|
||||
|
||||
public static byte[] hmac(String toEncode, byte[] key, Digest digest) {
|
||||
HMac hmac = new HMac(digest);
|
||||
byte[] resBuf = new byte[hmac.getMacSize()];
|
||||
byte[] plainBytes = Utils.encodeString(toEncode);
|
||||
|
@ -93,7 +98,7 @@ public class HttpUtils {
|
|||
hmac.init(new KeyParameter(keyBytes));
|
||||
hmac.update(plainBytes, 0, plainBytes.length);
|
||||
hmac.doFinal(resBuf, 0);
|
||||
return toBase64String(resBuf);
|
||||
return resBuf;
|
||||
}
|
||||
|
||||
public static String hmacSha1Base64(String toEncode, byte[] key)
|
||||
|
|
|
@ -0,0 +1,89 @@
|
|||
/**
|
||||
*
|
||||
* Copyright (C) 2009 Global Cloud Specialists, Inc. <info@globalcloudspecialists.com>
|
||||
*
|
||||
* ====================================================================
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
* ====================================================================
|
||||
*/
|
||||
package org.jclouds.http.functions;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkState;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.URI;
|
||||
|
||||
import javax.ws.rs.core.HttpHeaders;
|
||||
import javax.ws.rs.core.UriBuilder;
|
||||
|
||||
import org.jclouds.http.HttpException;
|
||||
import org.jclouds.http.HttpResponse;
|
||||
import org.jclouds.http.HttpResponseException;
|
||||
import org.jclouds.rest.InvocationContext;
|
||||
import org.jclouds.rest.internal.GeneratedHttpRequest;
|
||||
import org.jclouds.util.Utils;
|
||||
|
||||
import com.google.common.base.Function;
|
||||
|
||||
/**
|
||||
* parses a single URI from a list
|
||||
*
|
||||
* @author Adrian Cole
|
||||
*/
|
||||
public class ParseURIFromListOrLocationHeaderIf20x implements Function<HttpResponse, URI>,
|
||||
InvocationContext {
|
||||
private GeneratedHttpRequest<?> request;
|
||||
|
||||
public URI apply(HttpResponse from) {
|
||||
if (from.getStatusCode() > 206)
|
||||
throw new HttpException(String.format("Unhandled status code - %1$s", from));
|
||||
if ("text/uri-list".equals(from.getFirstHeaderOrNull(HttpHeaders.CONTENT_TYPE))) {
|
||||
try {
|
||||
if (from.getContent() == null)
|
||||
throw new HttpResponseException("no content", null, from);
|
||||
String toParse = Utils.toStringAndClose(from.getContent());
|
||||
return URI.create(toParse.trim());
|
||||
} catch (IOException e) {
|
||||
throw new HttpResponseException("couldn't parse uri from content", null, from, e);
|
||||
}
|
||||
} else {
|
||||
String location = from.getFirstHeaderOrNull(HttpHeaders.LOCATION);
|
||||
if (location == null)
|
||||
location = from.getFirstHeaderOrNull("location");
|
||||
if (location != null) {
|
||||
URI locationUri = URI.create(location);
|
||||
if (locationUri.getHost() != null)
|
||||
return locationUri;
|
||||
checkState(request != null, "request should have been initialized");
|
||||
|
||||
UriBuilder builder = UriBuilder.fromUri(URI.create("http://localhost/"+locationUri));
|
||||
builder.host(request.getEndpoint().getHost());
|
||||
builder.port(request.getEndpoint().getPort());
|
||||
builder.scheme(request.getEndpoint().getScheme());
|
||||
return builder.build();
|
||||
} else {
|
||||
throw new HttpResponseException("no uri in headers or content", null, from);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
public void setContext(GeneratedHttpRequest<?> request) {
|
||||
this.request = request;
|
||||
}
|
||||
}
|
|
@ -1,56 +0,0 @@
|
|||
/**
|
||||
*
|
||||
* Copyright (C) 2009 Global Cloud Specialists, Inc. <info@globalcloudspecialists.com>
|
||||
*
|
||||
* ====================================================================
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
* ====================================================================
|
||||
*/
|
||||
package org.jclouds.http.functions;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkState;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.URI;
|
||||
|
||||
import javax.ws.rs.core.HttpHeaders;
|
||||
|
||||
import org.jclouds.http.HttpResponse;
|
||||
import org.jclouds.http.HttpResponseException;
|
||||
import org.jclouds.util.Utils;
|
||||
|
||||
import com.google.common.base.Function;
|
||||
|
||||
/**
|
||||
* parses a single URI from a list
|
||||
*
|
||||
* @author Adrian Cole
|
||||
*/
|
||||
public class ParseURIList implements Function<HttpResponse, URI> {
|
||||
public URI apply(HttpResponse from) {
|
||||
try {
|
||||
checkState("text/uri-list".equals(from.getFirstHeaderOrNull(HttpHeaders.CONTENT_TYPE)),
|
||||
"response should have content type test/uri-list");
|
||||
|
||||
String toParse = Utils.toStringAndClose(from.getContent());
|
||||
return URI.create(toParse.trim());
|
||||
} catch (IOException e) {
|
||||
throw new HttpResponseException("couldn't parse url from response", null, from, e);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -62,7 +62,7 @@ import org.jclouds.http.HttpRequest;
|
|||
import org.jclouds.http.HttpRequestFilter;
|
||||
import org.jclouds.http.HttpResponse;
|
||||
import org.jclouds.http.functions.ParseSax;
|
||||
import org.jclouds.http.functions.ParseURIList;
|
||||
import org.jclouds.http.functions.ParseURIFromListOrLocationHeaderIf20x;
|
||||
import org.jclouds.http.functions.ReturnInputStream;
|
||||
import org.jclouds.http.functions.ReturnStringIf200;
|
||||
import org.jclouds.http.functions.ReturnTrueIf2xx;
|
||||
|
@ -529,7 +529,7 @@ public class RestAnnotationProcessor<T> {
|
|||
return ReturnVoidIf2xx.class;
|
||||
} else if (method.getReturnType().equals(URI.class)
|
||||
|| TypeLiteral.get(method.getGenericReturnType()).equals(futureURILiteral)) {
|
||||
return ParseURIList.class;
|
||||
return ParseURIFromListOrLocationHeaderIf20x.class;
|
||||
} else if (method.getReturnType().equals(InputStream.class)
|
||||
|| TypeLiteral.get(method.getGenericReturnType())
|
||||
.equals(futureInputStreamLiteral)) {
|
||||
|
|
|
@ -0,0 +1,181 @@
|
|||
/**
|
||||
*
|
||||
* Copyright (C) 2009 Global Cloud Specialists, Inc. <info@globalcloudspecialists.com>
|
||||
*
|
||||
* ====================================================================
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
* ====================================================================
|
||||
*/
|
||||
package org.jclouds.http.functions;
|
||||
|
||||
import static org.easymock.EasyMock.expect;
|
||||
import static org.easymock.classextension.EasyMock.createMock;
|
||||
import static org.easymock.classextension.EasyMock.replay;
|
||||
import static org.easymock.classextension.EasyMock.verify;
|
||||
import static org.testng.Assert.assertEquals;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.URI;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.TimeoutException;
|
||||
|
||||
import javax.ws.rs.ext.RuntimeDelegate;
|
||||
|
||||
import org.apache.commons.io.IOUtils;
|
||||
import org.jclouds.http.HttpResponse;
|
||||
import org.jclouds.rest.internal.GeneratedHttpRequest;
|
||||
import org.jclouds.rest.internal.RuntimeDelegateImpl;
|
||||
import org.mortbay.jetty.HttpHeaders;
|
||||
import org.testng.annotations.BeforeTest;
|
||||
import org.testng.annotations.Test;
|
||||
|
||||
import com.google.common.base.Function;
|
||||
|
||||
@Test(groups = { "unit" })
|
||||
public class ParseURIFromListOrLocationHeaderIf20xTest {
|
||||
|
||||
@Test
|
||||
public void testExceptionWhenNoContentOn200() throws ExecutionException, InterruptedException,
|
||||
TimeoutException, IOException {
|
||||
Function<HttpResponse, URI> function = new ParseURIFromListOrLocationHeaderIf20x();
|
||||
HttpResponse response = createMock(HttpResponse.class);
|
||||
expect(response.getStatusCode()).andReturn(200).atLeastOnce();
|
||||
expect(response.getFirstHeaderOrNull(HttpHeaders.CONTENT_TYPE)).andReturn("text/uri-list");
|
||||
expect(response.getContent()).andReturn(null);
|
||||
replay(response);
|
||||
try {
|
||||
function.apply(response);
|
||||
} catch (Exception e) {
|
||||
assert e.getMessage().equals("no content");
|
||||
}
|
||||
verify(response);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testExceptionWhenIOExceptionOn200() throws ExecutionException, InterruptedException,
|
||||
TimeoutException, IOException {
|
||||
Function<HttpResponse, URI> function = new ParseURIFromListOrLocationHeaderIf20x();
|
||||
HttpResponse response = createMock(HttpResponse.class);
|
||||
expect(response.getStatusCode()).andReturn(200).atLeastOnce();
|
||||
expect(response.getFirstHeaderOrNull(HttpHeaders.CONTENT_TYPE)).andReturn("text/uri-list");
|
||||
RuntimeException exception = new RuntimeException("bad");
|
||||
expect(response.getContent()).andThrow(exception);
|
||||
replay(response);
|
||||
try {
|
||||
function.apply(response);
|
||||
} catch (Exception e) {
|
||||
assert e.equals(exception);
|
||||
}
|
||||
verify(response);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testResponseOk() throws Exception {
|
||||
Function<HttpResponse, URI> function = new ParseURIFromListOrLocationHeaderIf20x();
|
||||
HttpResponse response = createMock(HttpResponse.class);
|
||||
expect(response.getStatusCode()).andReturn(200).atLeastOnce();
|
||||
expect(response.getFirstHeaderOrNull(HttpHeaders.CONTENT_TYPE)).andReturn("text/uri-list");
|
||||
expect(response.getContent()).andReturn(IOUtils.toInputStream("http://locahost"))
|
||||
.atLeastOnce();
|
||||
replay(response);
|
||||
assertEquals(function.apply(response), URI.create("http://locahost"));
|
||||
verify(response);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testResponseLocationOk() throws Exception {
|
||||
Function<HttpResponse, URI> function = new ParseURIFromListOrLocationHeaderIf20x();
|
||||
HttpResponse response = createMock(HttpResponse.class);
|
||||
expect(response.getStatusCode()).andReturn(200).atLeastOnce();
|
||||
expect(response.getFirstHeaderOrNull(HttpHeaders.CONTENT_TYPE)).andReturn("text/plain");
|
||||
expect(response.getFirstHeaderOrNull(HttpHeaders.LOCATION)).andReturn("http://locahost");
|
||||
replay(response);
|
||||
assertEquals(function.apply(response), URI.create("http://locahost"));
|
||||
verify(response);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testResponseLowercaseLocationOk() throws Exception {
|
||||
Function<HttpResponse, URI> function = new ParseURIFromListOrLocationHeaderIf20x();
|
||||
HttpResponse response = createMock(HttpResponse.class);
|
||||
expect(response.getStatusCode()).andReturn(200).atLeastOnce();
|
||||
expect(response.getFirstHeaderOrNull(HttpHeaders.CONTENT_TYPE)).andReturn("text/plain");
|
||||
expect(response.getFirstHeaderOrNull(HttpHeaders.LOCATION)).andReturn(null);
|
||||
expect(response.getFirstHeaderOrNull("location")).andReturn("http://locahost");
|
||||
replay(response);
|
||||
assertEquals(function.apply(response), URI.create("http://locahost"));
|
||||
verify(response);
|
||||
}
|
||||
|
||||
@BeforeTest
|
||||
public void beforeTest() {
|
||||
RuntimeDelegate.setInstance(new RuntimeDelegateImpl());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testResponsePathLocationOk() throws Exception {
|
||||
ParseURIFromListOrLocationHeaderIf20x function = new ParseURIFromListOrLocationHeaderIf20x();
|
||||
HttpResponse response = createMock(HttpResponse.class);
|
||||
GeneratedHttpRequest<?> request = createMock(GeneratedHttpRequest.class);
|
||||
function.setContext(request);
|
||||
expect(request.getEndpoint()).andReturn(URI.create("http://new/fd")).atLeastOnce();
|
||||
expect(response.getStatusCode()).andReturn(200).atLeastOnce();
|
||||
expect(response.getFirstHeaderOrNull(HttpHeaders.CONTENT_TYPE)).andReturn("text/plain");
|
||||
expect(response.getFirstHeaderOrNull(HttpHeaders.LOCATION)).andReturn("path");
|
||||
replay(request);
|
||||
replay(response);
|
||||
assertEquals(function.apply(response), URI.create("http://new/path"));
|
||||
verify(request);
|
||||
verify(response);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testResponsePathPortLocationOk() throws Exception {
|
||||
ParseURIFromListOrLocationHeaderIf20x function = new ParseURIFromListOrLocationHeaderIf20x();
|
||||
HttpResponse response = createMock(HttpResponse.class);
|
||||
GeneratedHttpRequest<?> request = createMock(GeneratedHttpRequest.class);
|
||||
function.setContext(request);
|
||||
expect(request.getEndpoint()).andReturn(URI.create("http://new:8080/fd")).atLeastOnce();
|
||||
expect(response.getStatusCode()).andReturn(200).atLeastOnce();
|
||||
expect(response.getFirstHeaderOrNull(HttpHeaders.CONTENT_TYPE)).andReturn("text/plain");
|
||||
expect(response.getFirstHeaderOrNull(HttpHeaders.LOCATION)).andReturn("path");
|
||||
replay(request);
|
||||
replay(response);
|
||||
assertEquals(function.apply(response), URI.create("http://new:8080/path"));
|
||||
verify(request);
|
||||
verify(response);
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testResponsePathSchemeLocationOk() throws Exception {
|
||||
ParseURIFromListOrLocationHeaderIf20x function = new ParseURIFromListOrLocationHeaderIf20x();
|
||||
HttpResponse response = createMock(HttpResponse.class);
|
||||
GeneratedHttpRequest<?> request = createMock(GeneratedHttpRequest.class);
|
||||
function.setContext(request);
|
||||
expect(request.getEndpoint()).andReturn(URI.create("https://new/fd")).atLeastOnce();
|
||||
expect(response.getStatusCode()).andReturn(200).atLeastOnce();
|
||||
expect(response.getFirstHeaderOrNull(HttpHeaders.CONTENT_TYPE)).andReturn("text/plain");
|
||||
expect(response.getFirstHeaderOrNull(HttpHeaders.LOCATION)).andReturn("path");
|
||||
replay(request);
|
||||
replay(response);
|
||||
assertEquals(function.apply(response), URI.create("https://new/path"));
|
||||
verify(request);
|
||||
verify(response);
|
||||
}
|
||||
}
|
|
@ -62,7 +62,7 @@ import org.jclouds.http.HttpRequest;
|
|||
import org.jclouds.http.HttpRequestFilter;
|
||||
import org.jclouds.http.HttpResponse;
|
||||
import org.jclouds.http.config.JavaUrlHttpCommandExecutorServiceModule;
|
||||
import org.jclouds.http.functions.ParseURIList;
|
||||
import org.jclouds.http.functions.ParseURIFromListOrLocationHeaderIf20x;
|
||||
import org.jclouds.http.functions.ReturnInputStream;
|
||||
import org.jclouds.http.functions.ReturnStringIf200;
|
||||
import org.jclouds.http.functions.ReturnTrueIf2xx;
|
||||
|
@ -991,7 +991,7 @@ public class RestAnnotationProcessorTest {
|
|||
Method method = TestTransformers.class.getMethod("uri");
|
||||
Class<? extends Function<HttpResponse, ?>> transformer = factory(TestTransformers.class)
|
||||
.getParserOrThrowException(method);
|
||||
assertEquals(transformer, ParseURIList.class);
|
||||
assertEquals(transformer, ParseURIFromListOrLocationHeaderIf20x.class);
|
||||
}
|
||||
|
||||
@SuppressWarnings("static-access")
|
||||
|
@ -999,7 +999,7 @@ public class RestAnnotationProcessorTest {
|
|||
Method method = TestTransformers.class.getMethod("futureUri");
|
||||
Class<? extends Function<HttpResponse, ?>> transformer = factory(TestTransformers.class)
|
||||
.getParserOrThrowException(method);
|
||||
assertEquals(transformer, ParseURIList.class);
|
||||
assertEquals(transformer, ParseURIFromListOrLocationHeaderIf20x.class);
|
||||
}
|
||||
|
||||
public static class ReturnStringIf200Context extends ReturnStringIf200 implements
|
||||
|
|
Loading…
Reference in New Issue