You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cxf.apache.org by se...@apache.org on 2011/12/05 12:59:29 UTC
svn commit: r1210420 - in /cxf/trunk:
rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/cors/
systests/jaxrs/src/test/java/org/apache/cxf/systest/jaxrs/
systests/jaxrs/src/test/java/org/apache/cxf/systest/jaxrs/cors/
Author: sergeyb
Date: Mon Dec 5 11:59:29 2011
New Revision: 1210420
URL: http://svn.apache.org/viewvc?rev=1210420&view=rev
Log:
[CXF-3943] Using JAX-RS Runtime to confirm a resource method exists during a preflight check
Removed:
cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/cors/CrossOriginResourceSharingPaths.java
Modified:
cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/cors/CrossOriginResourceSharing.java
cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/cors/CrossOriginResourceSharingFilter.java
cxf/trunk/systests/jaxrs/src/test/java/org/apache/cxf/systest/jaxrs/JAXRSClientServerBookTest.java
cxf/trunk/systests/jaxrs/src/test/java/org/apache/cxf/systest/jaxrs/cors/AnnotatedCorsServer.java
cxf/trunk/systests/jaxrs/src/test/java/org/apache/cxf/systest/jaxrs/cors/UnannotatedCorsServer.java
Modified: cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/cors/CrossOriginResourceSharing.java
URL: http://svn.apache.org/viewvc/cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/cors/CrossOriginResourceSharing.java?rev=1210420&r1=1210419&r2=1210420&view=diff
==============================================================================
--- cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/cors/CrossOriginResourceSharing.java (original)
+++ cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/cors/CrossOriginResourceSharing.java Mon Dec 5 11:59:29 2011
@@ -55,11 +55,6 @@ public @interface CrossOriginResourceSha
*/
String[] allowOrigins() default { };
/**
- * A list of HTTP methods. This is used only for preflight,
- * and is only valid on a class.
- */
- String[] allowMethods() default { };
- /**
* A list of headers that the client may include
* in an actual request.
*/
@@ -90,9 +85,4 @@ public @interface CrossOriginResourceSha
*/
boolean localPreflight() default false;
- /**
- * For use inside @{@link CrossOriginResourceSharingPaths}. The path to apply the
- * policies to.
- */
- String path() default "";
}
Modified: cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/cors/CrossOriginResourceSharingFilter.java
URL: http://svn.apache.org/viewvc/cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/cors/CrossOriginResourceSharingFilter.java?rev=1210420&r1=1210419&r2=1210420&view=diff
==============================================================================
--- cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/cors/CrossOriginResourceSharingFilter.java (original)
+++ cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/cors/CrossOriginResourceSharingFilter.java Mon Dec 5 11:59:29 2011
@@ -19,6 +19,7 @@
package org.apache.cxf.jaxrs.cors;
+import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
@@ -27,16 +28,23 @@ import java.util.regex.Pattern;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.HttpHeaders;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.MultivaluedMap;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.Response.ResponseBuilder;
import org.apache.cxf.common.util.ReflectionUtil;
+import org.apache.cxf.jaxrs.JAXRSServiceImpl;
import org.apache.cxf.jaxrs.ext.RequestHandler;
import org.apache.cxf.jaxrs.ext.ResponseHandler;
+import org.apache.cxf.jaxrs.impl.MetadataMap;
import org.apache.cxf.jaxrs.model.ClassResourceInfo;
import org.apache.cxf.jaxrs.model.OperationResourceInfo;
+import org.apache.cxf.jaxrs.model.URITemplate;
import org.apache.cxf.jaxrs.utils.HttpUtils;
+import org.apache.cxf.jaxrs.utils.JAXRSUtils;
import org.apache.cxf.message.Message;
+import org.apache.cxf.service.Service;
/**
* An single class that provides both an input and an output filter for CORS, following
@@ -65,7 +73,6 @@ public class CrossOriginResourceSharingF
* deployment.
*/
private List<String> allowOrigins = Collections.emptyList();
- private List<String> allowMethods = Collections.emptyList();
private List<String> allowHeaders = Collections.emptyList();
private boolean allowAllOrigins;
private boolean allowCredentials;
@@ -172,32 +179,18 @@ public class CrossOriginResourceSharingF
return null;
}
String requestMethod = requestMethodValues.get(0);
-
/*
* CORS doesn't send enough information with a preflight to accurately identity the single method
- * that will handle the request. CrossOriginResourceSharingPaths provides annotations by path/method
- * for this case. If none of those apply, a plain class level CrossOrginResourceSharing is the
- * best we can do.
+ * that will handle the request. We ask the JAX-RS runtime to find the matching method which is
+ * expected to have a CrossOriginResourceSharing annotation set.
*/
- String requestUri = HttpUtils.getPathToMatch(m, true);
- CrossOriginResourceSharing ann = null;
- CrossOriginResourceSharingPaths classPathsAnn =
- resourceClass.getResourceClass().getAnnotation(CrossOriginResourceSharingPaths.class);
- if (classPathsAnn != null) {
- /* search the path/method pair. */
- for (CrossOriginResourceSharing pathAnn : classPathsAnn.value()) {
- /* A very simple path policy! If someone wants to turn this into
- * searching up the tree, they are welcome.
- */
- if (pathAnn.path() != null && pathAnn.path().equals(requestUri)
- && Arrays.asList(pathAnn.allowMethods()).contains(requestMethod)) {
- ann = pathAnn;
- break;
- }
- }
- }
+
+ Method method = getPreflightMethod(m, requestMethod);
+
+ CrossOriginResourceSharing ann = method.getAnnotation(CrossOriginResourceSharing.class);
+ ann = ann == null ? optionAnn : ann;
if (ann == null) {
- ann = resourceClass.getResourceClass().getAnnotation(CrossOriginResourceSharing.class);
+ return null;
}
// 5.2.2 must be on the list or we must be matching *.
@@ -210,11 +203,7 @@ public class CrossOriginResourceSharingF
List<String> requestHeaders = getHeaderValues(CorsHeaderConstants.HEADER_AC_REQUEST_HEADERS, false);
// 5.2.5 reject if the method is not on the list.
- List<String> effectiveAllowMethods = effectiveAllowMethods(ann);
-
- if (!effectiveAllowMethods.contains(requestMethod)) {
- return null;
- }
+ // This was indirectly enforced by getCorsMethod()
// 5.2.6 reject if the header is not listed.
if (!effectiveAllowHeaders(ann).containsAll(requestHeaders)) {
@@ -248,6 +237,58 @@ public class CrossOriginResourceSharingF
}
//CHECKSTYLE:ON
+ private Method getPreflightMethod(Message m, String httpMethod) {
+ String requestUri = HttpUtils.getPathToMatch(m, true);
+
+ Service service = m.getExchange().get(Service.class);
+ List<ClassResourceInfo> resources = ((JAXRSServiceImpl)service).getClassResourceInfos();
+ MultivaluedMap<String, String> values = new MetadataMap<String, String>();
+ ClassResourceInfo resource = JAXRSUtils.selectResourceClass(resources,
+ requestUri,
+ values,
+ m);
+ if (resource == null) {
+ return null;
+ }
+ OperationResourceInfo ori = findPreflightMethod(resource, requestUri, httpMethod, values, m);
+ return ori == null ? null : ori.getAnnotatedMethod();
+ }
+
+
+ private OperationResourceInfo findPreflightMethod(ClassResourceInfo resource,
+ String requestUri,
+ String httpMethod,
+ MultivaluedMap<String, String> values,
+ Message m) {
+ final String contentType = MediaType.WILDCARD;
+ final MediaType acceptType = MediaType.WILDCARD_TYPE;
+ OperationResourceInfo ori = JAXRSUtils.findTargetMethod(resource,
+ m, httpMethod, values,
+ contentType,
+ Collections.singletonList(acceptType),
+ true);
+ if (ori == null) {
+ return null;
+ }
+ if (ori.isSubResourceLocator()) {
+ Class<?> cls = ori.getMethodToInvoke().getReturnType();
+ ClassResourceInfo subcri = resource.getSubResource(cls, cls);
+ if (subcri == null) {
+ return null;
+ } else {
+ MultivaluedMap<String, String> newValues = new MetadataMap<String, String>();
+ newValues.putAll(values);
+ return findPreflightMethod(subcri,
+ values.getFirst(URITemplate.FINAL_MATCH_GROUP),
+ httpMethod,
+ newValues,
+ m);
+ }
+ } else {
+ return ori;
+ }
+ }
+
private void commonRequestProcessing(Message m, CrossOriginResourceSharing ann, String origin) {
m.getExchange().put(CorsHeaderConstants.HEADER_ORIGIN, origin);
@@ -331,17 +372,6 @@ public class CrossOriginResourceSharingF
}
}
- private List<String> effectiveAllowMethods(CrossOriginResourceSharing ann) {
- if (ann != null) {
- if (ann.allowMethods() == null) {
- return Collections.emptyList();
- }
- return Arrays.asList(ann.allowMethods());
- } else {
- return allowMethods;
- }
- }
-
private List<String> effectiveAllowHeaders(CrossOriginResourceSharing ann) {
if (ann != null) {
if (ann.allowHeaders() == null) {
@@ -461,19 +491,7 @@ public class CrossOriginResourceSharingF
this.allowAllOrigins = allowAllOrigins;
}
- public List<String> getAllowMethods() {
- return allowMethods;
- }
-
- /**
- * The list of allowed non-simple methods for preflight checks. Section 5.2.3.
- *
- * @param allowedMethods a list of case-sensitive HTTP method names.
- */
- public void setAllowMethods(List<String> allowedMethods) {
- this.allowMethods = allowedMethods;
- }
-
+
public List<String> getAllowHeaders() {
return allowHeaders;
}
Modified: cxf/trunk/systests/jaxrs/src/test/java/org/apache/cxf/systest/jaxrs/JAXRSClientServerBookTest.java
URL: http://svn.apache.org/viewvc/cxf/trunk/systests/jaxrs/src/test/java/org/apache/cxf/systest/jaxrs/JAXRSClientServerBookTest.java?rev=1210420&r1=1210419&r2=1210420&view=diff
==============================================================================
--- cxf/trunk/systests/jaxrs/src/test/java/org/apache/cxf/systest/jaxrs/JAXRSClientServerBookTest.java (original)
+++ cxf/trunk/systests/jaxrs/src/test/java/org/apache/cxf/systest/jaxrs/JAXRSClientServerBookTest.java Mon Dec 5 11:59:29 2011
@@ -71,7 +71,7 @@ public class JAXRSClientServerBookTest e
@BeforeClass
public static void startServers() throws Exception {
assertTrue("server did not launch correctly",
- launchServer(BookServer.class));
+ launchServer(BookServer.class, true));
}
@Test
Modified: cxf/trunk/systests/jaxrs/src/test/java/org/apache/cxf/systest/jaxrs/cors/AnnotatedCorsServer.java
URL: http://svn.apache.org/viewvc/cxf/trunk/systests/jaxrs/src/test/java/org/apache/cxf/systest/jaxrs/cors/AnnotatedCorsServer.java?rev=1210420&r1=1210419&r2=1210420&view=diff
==============================================================================
--- cxf/trunk/systests/jaxrs/src/test/java/org/apache/cxf/systest/jaxrs/cors/AnnotatedCorsServer.java (original)
+++ cxf/trunk/systests/jaxrs/src/test/java/org/apache/cxf/systest/jaxrs/cors/AnnotatedCorsServer.java Mon Dec 5 11:59:29 2011
@@ -39,9 +39,7 @@ import org.apache.cxf.jaxrs.cors.CrossOr
*/
@CrossOriginResourceSharing(allowOrigins = {
"http://area51.mil:31415"
- }, allowCredentials = true, maxAge = 1, allowMethods = {
- "PUT"
- }, allowHeaders = {
+ }, allowCredentials = true, maxAge = 1, allowHeaders = {
"X-custom-1", "X-custom-2"
}, exposeHeaders = {
"X-custom-3", "X-custom-4"
Modified: cxf/trunk/systests/jaxrs/src/test/java/org/apache/cxf/systest/jaxrs/cors/UnannotatedCorsServer.java
URL: http://svn.apache.org/viewvc/cxf/trunk/systests/jaxrs/src/test/java/org/apache/cxf/systest/jaxrs/cors/UnannotatedCorsServer.java?rev=1210420&r1=1210419&r2=1210420&view=diff
==============================================================================
--- cxf/trunk/systests/jaxrs/src/test/java/org/apache/cxf/systest/jaxrs/cors/UnannotatedCorsServer.java (original)
+++ cxf/trunk/systests/jaxrs/src/test/java/org/apache/cxf/systest/jaxrs/cors/UnannotatedCorsServer.java Mon Dec 5 11:59:29 2011
@@ -29,20 +29,10 @@ import javax.ws.rs.Produces;
import javax.ws.rs.core.Response;
import org.apache.cxf.jaxrs.cors.CrossOriginResourceSharing;
-import org.apache.cxf.jaxrs.cors.CrossOriginResourceSharingPaths;
/**
* Service bean with no class-level annotation for cross-script control.
*/
-@CrossOriginResourceSharingPaths(
- @CrossOriginResourceSharing(path = "/annotatedPut",
- allowOrigins = { "http://area51.mil:31415" },
- allowCredentials = true,
- maxAge = 1,
- allowMethods = { "PUT" },
- allowHeaders = { "X-custom-1", "X-custom-2" },
- exposeHeaders = {"X-custom-3", "X-custom-4" }
- ))
public class UnannotatedCorsServer {
@GET
@@ -78,6 +68,13 @@ public class UnannotatedCorsServer {
@Consumes("text/plain")
@Produces("text/plain")
@Path("/annotatedPut")
+ @CrossOriginResourceSharing(
+ allowOrigins = { "http://area51.mil:31415" },
+ allowCredentials = true,
+ maxAge = 1,
+ allowHeaders = { "X-custom-1", "X-custom-2" },
+ exposeHeaders = {"X-custom-3", "X-custom-4" }
+ )
public String annotatedPut(String input) {
return input;
}