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:
adrian.f.cole 2009-10-19 01:11:34 +00:00
parent eefd7d47f8
commit ff9abb6884
6 changed files with 281 additions and 62 deletions

View File

@ -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)

View File

@ -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;
}
}

View File

@ -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);
}
}
}

View File

@ -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)) {

View File

@ -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);
}
}

View File

@ -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