You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@olingo.apache.org by ra...@apache.org on 2016/03/16 18:27:30 UTC

olingo-odata4 git commit: OLINGO-908: Adding 'Allow' header in situations of returning 405 for the submitted request

Repository: olingo-odata4
Updated Branches:
  refs/heads/master 860d418fd -> 9c61e2237


OLINGO-908: Adding 'Allow' header in situations of returning 405 for the submitted request


Project: http://git-wip-us.apache.org/repos/asf/olingo-odata4/repo
Commit: http://git-wip-us.apache.org/repos/asf/olingo-odata4/commit/9c61e223
Tree: http://git-wip-us.apache.org/repos/asf/olingo-odata4/tree/9c61e223
Diff: http://git-wip-us.apache.org/repos/asf/olingo-odata4/diff/9c61e223

Branch: refs/heads/master
Commit: 9c61e223756f40a0a87ebc2cf6297ef5fd69fc70
Parents: 860d418
Author: Ramesh Reddy <ra...@jboss.org>
Authored: Wed Mar 16 12:27:04 2016 -0500
Committer: Ramesh Reddy <ra...@jboss.org>
Committed: Wed Mar 16 12:27:04 2016 -0500

----------------------------------------------------------------------
 .../olingo/server/core/ServiceRequest.java      |  56 ++++++-
 .../server/core/requests/ActionRequest.java     |  11 +-
 .../server/core/requests/BatchRequest.java      |  10 +-
 .../server/core/requests/DataRequest.java       | 156 +++++++++++++------
 .../server/core/requests/FunctionRequest.java   |  25 ++-
 .../server/core/requests/MediaRequest.java      |  16 +-
 .../server/core/requests/MetadataRequest.java   |   5 +-
 .../core/requests/ServiceDocumentRequest.java   |   6 +-
 .../server/example/TripPinServiceTest.java      |   8 +
 9 files changed, 211 insertions(+), 82 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/9c61e223/lib/server-core-ext/src/main/java/org/apache/olingo/server/core/ServiceRequest.java
----------------------------------------------------------------------
diff --git a/lib/server-core-ext/src/main/java/org/apache/olingo/server/core/ServiceRequest.java b/lib/server-core-ext/src/main/java/org/apache/olingo/server/core/ServiceRequest.java
index f6b3296..6242975 100644
--- a/lib/server-core-ext/src/main/java/org/apache/olingo/server/core/ServiceRequest.java
+++ b/lib/server-core-ext/src/main/java/org/apache/olingo/server/core/ServiceRequest.java
@@ -81,10 +81,38 @@ public abstract class ServiceRequest {
     this.uriInfo = uriInfo;
   }
 
-  public boolean allowedMethod() {
-    return isGET();
+  public static boolean  assertHttpMethod(HttpMethod issued, HttpMethod[] allowedMethods,
+      ODataResponse response) throws ODataHandlerException {
+    boolean allowed = false; 
+    for (HttpMethod method :allowedMethods) {
+      if (issued.equals(method)) {
+        allowed = true;
+      }
+    }
+    if (!allowed) {
+      return methodNotAllowed(response, issued, null, allowedMethods); 
+    }
+    return true;
   }
+  
+  public boolean assertHttpMethod(ODataResponse response) throws ODataHandlerException {
+    boolean allowed = false; 
+    HttpMethod issued = this.request.getMethod();
+    for (HttpMethod method :allowedMethods()) {
+      if (issued.equals(method)) {
+        allowed = true;
+      }
+    }
+    if (!allowed) {
+      return methodNotAllowed(response, issued, null, allowedMethods()); 
+    }
+    return true;
+  }  
 
+  public HttpMethod[] allowedMethods() {
+    return new HttpMethod[] {HttpMethod.GET};
+  }
+  
   public CustomContentTypeSupport getCustomContentTypeSupport() {
     return this.customContentType;
   }
@@ -113,10 +141,22 @@ public abstract class ServiceRequest {
 
   public abstract ContentType getResponseContentType() throws ContentNegotiatorException;
 
-  public void methodNotAllowed() throws ODataHandlerException {
-    throw new ODataHandlerException("HTTP method " + this.request.getMethod() + " is not allowed.",
-        ODataHandlerException.MessageKeys.HTTP_METHOD_NOT_ALLOWED, this.request.getMethod()
-            .toString());
+  public static boolean methodNotAllowed(ODataResponse response, HttpMethod issued, String reason,
+      HttpMethod... allowed) throws ODataHandlerException {
+    
+    StringBuilder sb = new StringBuilder();
+    for (HttpMethod method:allowed) {
+      if (sb.length() > 0) {
+        sb.append(",");
+      }
+      sb.append(method.name());
+    }
+    response.setHeader("Allow", sb.toString());
+    if (reason == null) {
+      reason = "HTTP method " + issued + " is not allowed.";
+    }
+    throw new ODataHandlerException(reason,
+        ODataHandlerException.MessageKeys.HTTP_METHOD_NOT_ALLOWED, issued.name());
   }
 
   public void notImplemented() throws ODataHandlerException {
@@ -143,6 +183,10 @@ public abstract class ServiceRequest {
   protected boolean isPOST() {
     return this.request.getMethod() == HttpMethod.POST;
   }
+  
+  protected HttpMethod httpMethod() {
+    return this.request.getMethod();
+  }  
 
   private static FullQualifiedName XML10_CHAR_REPLACE_FQN = new FullQualifiedName(
       "org.apache.olingo.v1.xml10-incompatible-char-replacement");

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/9c61e223/lib/server-core-ext/src/main/java/org/apache/olingo/server/core/requests/ActionRequest.java
----------------------------------------------------------------------
diff --git a/lib/server-core-ext/src/main/java/org/apache/olingo/server/core/requests/ActionRequest.java b/lib/server-core-ext/src/main/java/org/apache/olingo/server/core/requests/ActionRequest.java
index 501b110..0dc61b8 100644
--- a/lib/server-core-ext/src/main/java/org/apache/olingo/server/core/requests/ActionRequest.java
+++ b/lib/server-core-ext/src/main/java/org/apache/olingo/server/core/requests/ActionRequest.java
@@ -27,6 +27,7 @@ import org.apache.olingo.commons.api.data.ContextURL;
 import org.apache.olingo.commons.api.data.Parameter;
 import org.apache.olingo.commons.api.edm.EdmAction;
 import org.apache.olingo.commons.api.edm.EdmReturnType;
+import org.apache.olingo.commons.api.http.HttpMethod;
 import org.apache.olingo.server.api.OData;
 import org.apache.olingo.server.api.ODataApplicationException;
 import org.apache.olingo.server.api.ODataLibraryException;
@@ -54,9 +55,9 @@ public class ActionRequest extends OperationRequest {
   public void execute(ServiceHandler handler, ODataResponse response)
       throws ODataLibraryException, ODataApplicationException {
 
-    if (!allowedMethod()) {
-      methodNotAllowed();
-    }
+    // check for valid HTTP Verb
+    assertHttpMethod(response);
+    
     // Actions MAY return data but MUST NOT be further composed with additional
     // path segments.
     // On success, the response is 201 Created for actions that create entities,
@@ -85,9 +86,9 @@ public class ActionRequest extends OperationRequest {
   }
 
   @Override
-  public boolean allowedMethod() {
+  public HttpMethod[] allowedMethods() {
     // 11.5.4.1 Invoking an Action - only allows POST
-    return (isPOST());
+    return new HttpMethod[] {HttpMethod.POST};
   }
   
   @SuppressWarnings("unchecked")

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/9c61e223/lib/server-core-ext/src/main/java/org/apache/olingo/server/core/requests/BatchRequest.java
----------------------------------------------------------------------
diff --git a/lib/server-core-ext/src/main/java/org/apache/olingo/server/core/requests/BatchRequest.java b/lib/server-core-ext/src/main/java/org/apache/olingo/server/core/requests/BatchRequest.java
index 2215594..8394a54 100644
--- a/lib/server-core-ext/src/main/java/org/apache/olingo/server/core/requests/BatchRequest.java
+++ b/lib/server-core-ext/src/main/java/org/apache/olingo/server/core/requests/BatchRequest.java
@@ -26,6 +26,7 @@ import java.util.UUID;
 
 import org.apache.olingo.commons.api.format.ContentType;
 import org.apache.olingo.commons.api.http.HttpHeader;
+import org.apache.olingo.commons.api.http.HttpMethod;
 import org.apache.olingo.commons.api.http.HttpStatusCode;
 import org.apache.olingo.server.api.OData;
 import org.apache.olingo.server.api.ODataApplicationException;
@@ -57,9 +58,8 @@ public class BatchRequest extends ServiceRequest {
   public void execute(ServiceHandler handler, ODataResponse response)
       throws ODataLibraryException, ODataApplicationException {
 
-    if (!allowedMethod()) {
-      methodNotAllowed();
-    }
+    // check for valid HTTP Verb
+    assertHttpMethod(response);
 
     validateContentType();
     boolean continueOnError = isContinueOnError();
@@ -165,8 +165,8 @@ public class BatchRequest extends ServiceRequest {
   }
 
   @Override
-  public boolean allowedMethod() {
-    return isPOST();
+  public HttpMethod[] allowedMethods() {
+    return new HttpMethod[] {HttpMethod.POST};
   }
 
   private void validateContentType() throws ODataApplicationException {

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/9c61e223/lib/server-core-ext/src/main/java/org/apache/olingo/server/core/requests/DataRequest.java
----------------------------------------------------------------------
diff --git a/lib/server-core-ext/src/main/java/org/apache/olingo/server/core/requests/DataRequest.java b/lib/server-core-ext/src/main/java/org/apache/olingo/server/core/requests/DataRequest.java
index 45e1ed6..fecc8b8 100644
--- a/lib/server-core-ext/src/main/java/org/apache/olingo/server/core/requests/DataRequest.java
+++ b/lib/server-core-ext/src/main/java/org/apache/olingo/server/core/requests/DataRequest.java
@@ -46,6 +46,7 @@ import org.apache.olingo.commons.api.edm.EdmProperty;
 import org.apache.olingo.commons.api.ex.ODataRuntimeException;
 import org.apache.olingo.commons.api.format.ContentType;
 import org.apache.olingo.commons.api.http.HttpHeader;
+import org.apache.olingo.commons.api.http.HttpMethod;
 import org.apache.olingo.server.api.OData;
 import org.apache.olingo.server.api.ODataApplicationException;
 import org.apache.olingo.server.api.ODataLibraryException;
@@ -71,6 +72,7 @@ import org.apache.olingo.server.api.uri.UriResourceProperty;
 import org.apache.olingo.server.api.uri.UriResourceSingleton;
 import org.apache.olingo.server.core.ContentNegotiator;
 import org.apache.olingo.server.core.ContentNegotiatorException;
+import org.apache.olingo.server.core.ODataHandlerException;
 import org.apache.olingo.server.core.ReturnRepresentation;
 import org.apache.olingo.server.core.ServiceHandler;
 import org.apache.olingo.server.core.ServiceRequest;
@@ -99,8 +101,10 @@ public class DataRequest extends ServiceRequest {
    * This sub-categorizes the request so that code can be simplified
    */
   interface RequestType {
-    public boolean allowedMethod();
-
+    public HttpMethod[] allowedMethods();
+    
+    public boolean assertHttpMethod(ODataResponse response) throws ODataHandlerException;
+    
     public ContentType getResponseContentType() throws ContentNegotiatorException;
 
     public ContextURL getContextURL(OData odata) throws SerializerException;
@@ -212,6 +216,7 @@ public class DataRequest extends ServiceRequest {
     return valueRequest;
   }
 
+  /*
   private boolean hasMediaStream() {
     return this.uriResourceEntitySet != null && this.uriResourceEntitySet.getEntityType().hasStream();
   }
@@ -219,15 +224,21 @@ public class DataRequest extends ServiceRequest {
   private InputStream getMediaStream() {
     return this.request.getBody();
   }
-
+  */
+  
   public void setValueRequest(boolean valueRequest) {
     this.valueRequest = valueRequest;
     this.type = new ValueRequest();
   }
 
+  public boolean assertHttpMethod(ODataResponse response)
+      throws ODataHandlerException {
+    return this.type.assertHttpMethod(response);
+  }
+  
   @Override
-  public boolean allowedMethod() {
-    return this.type.allowedMethod();
+  public HttpMethod[] allowedMethods() {
+    return this.type.allowedMethods();
   }
 
   public ContextURL getContextURL(OData odata) throws SerializerException {
@@ -238,9 +249,8 @@ public class DataRequest extends ServiceRequest {
   public void execute(ServiceHandler handler, ODataResponse response)
       throws ODataLibraryException, ODataApplicationException {
 
-    if (!this.type.allowedMethod()) {
-      methodNotAllowed();
-    }
+    // check for valid HTTP Verb
+    assertHttpMethod(response);
 
     this.type.execute(handler, response);
   }
@@ -273,26 +283,37 @@ public class DataRequest extends ServiceRequest {
   class EntityRequest implements RequestType {
 
     @Override
-    public boolean allowedMethod() {
+    public boolean assertHttpMethod(ODataResponse response) throws ODataHandlerException {
       // the create/update/delete to navigation property is done through references
       // see # 11.4.6
       if (!getNavigations().isEmpty() && !isGET()) {
-        return false;
+        return methodNotAllowed(response, httpMethod(), 
+            "create/update/delete to navigation property is done through references", 
+            allowedMethods());
       }
       
       if ((isGET() || isDELETE()) && getReturnRepresentation() != ReturnRepresentation.NONE) {
-        return false;
+        return methodNotAllowed(response, httpMethod(), 
+            "Invalid prefer header used", 
+            allowedMethods());
       }
       
       // in update, delete entity cases, predicate must be there
       if ((isPATCH() || isPUT() || isDELETE()) 
           && (getKeyPredicates() == null || getKeyPredicates().isEmpty())) {
-        return false;
+        return methodNotAllowed(response, httpMethod(),
+            "No key predicates provided",allowedMethods());
       }
-      return true;
+      return ServiceRequest.assertHttpMethod(httpMethod(), allowedMethods(), response);
     }
 
     @Override
+    public HttpMethod[] allowedMethods() {
+      return new HttpMethod[] { HttpMethod.GET, HttpMethod.POST, HttpMethod.PUT,
+          HttpMethod.PATCH, HttpMethod.DELETE };
+    }     
+    
+    @Override
     public ContentType getResponseContentType() throws ContentNegotiatorException {
       return ContentNegotiator.doContentNegotiation(uriInfo.getFormatOption(), getODataRequest(),
           getCustomContentTypeSupport(), isCollection() ? RepresentationType.COLLECTION_ENTITY
@@ -359,15 +380,20 @@ public class DataRequest extends ServiceRequest {
   class CountRequest implements RequestType {
 
     @Override
-    public boolean allowedMethod() {
+    public boolean assertHttpMethod(ODataResponse response) throws ODataHandlerException {
       if (getReturnRepresentation() != ReturnRepresentation.NONE) {
-        return false;
+        return methodNotAllowed(response, httpMethod(), "Invalid Prefer header used", 
+            allowedMethods());
       }
-
-      return isGET();
+      return ServiceRequest.assertHttpMethod(httpMethod(), allowedMethods(), response);
     }
 
     @Override
+    public HttpMethod[] allowedMethods() {
+      return new HttpMethod[] { HttpMethod.GET};
+    }     
+    
+    @Override
     public ContentType getResponseContentType() throws ContentNegotiatorException {
       return ContentType.TEXT_PLAIN;
     }
@@ -390,35 +416,42 @@ public class DataRequest extends ServiceRequest {
   class ReferenceRequest implements RequestType {
 
     @Override
-    public boolean allowedMethod() {
+    public boolean assertHttpMethod(ODataResponse response) throws ODataHandlerException {
       if ((isGET() || isDELETE()) && getReturnRepresentation() != ReturnRepresentation.NONE) {
-        return false;
+        return methodNotAllowed(response, httpMethod(), "Invalid Prefer header used", 
+            allowedMethods());
       }
       
       // references are only allowed on the navigation properties
       if (getNavigations().isEmpty()) {
-        return false;
+        return methodNotAllowed(response, httpMethod(),
+            "References can be only used on navigation properties",
+            allowedMethods());
       }
 
       // 11.4.6.1 - post allowed on only collection valued navigation
       if (isPOST() && !getNavigations().getLast().isCollection()) {
-        return false;
+        return methodNotAllowed(response, httpMethod(),
+            "POST only allowed on collection valued navigation",
+            allowedMethods());
       }
 
       // 11.4.6.3 - PUT allowed on single valued navigation
       if (isPUT() && getNavigations().getLast().isCollection()) {
-        return false;
-      }
-
-      // No defined behavior in spec
-      if (isPATCH()) {
-        return false;
+        return methodNotAllowed(response, httpMethod(),
+            "PUT only allowed on single valued navigation", allowedMethods());
       }
-
-      return true;
+      //PATCH is not defined in spec
+      return ServiceRequest.assertHttpMethod(httpMethod(), allowedMethods(), response);
     }
 
     @Override
+    public HttpMethod[] allowedMethods() {
+      return new HttpMethod[] { HttpMethod.GET, HttpMethod.POST, HttpMethod.PUT,
+          HttpMethod.DELETE };
+    }
+    
+    @Override
     public ContentType getResponseContentType() throws ContentNegotiatorException {
       return ContentNegotiator.doContentNegotiation(uriInfo.getFormatOption(), getODataRequest(),
           getCustomContentTypeSupport(), isCollection() ? RepresentationType.COLLECTION_REFERENCE
@@ -486,26 +519,34 @@ public class DataRequest extends ServiceRequest {
   class PropertyRequest implements RequestType {
 
     @Override
-    public boolean allowedMethod() {
-      if ((isGET() || isDELETE() || isPropertyStream()) && getReturnRepresentation() != ReturnRepresentation.NONE) {
-        return false;
+    public boolean assertHttpMethod(ODataResponse response) throws ODataHandlerException {
+      if ((isGET() || isDELETE() || isPropertyStream())
+          && getReturnRepresentation() != ReturnRepresentation.NONE) {
+        return methodNotAllowed(response, httpMethod(), "Invalid Prefer header used", 
+            allowedMethods());
       }
       
       // create of properties is not allowed,
       // only read, update, delete. Note that delete is
       // same as update with null
-      if (isPOST()) {
-        return false;
-      }
 
       // 11.4.9.4, collection properties are not supported with merge
       if (isPATCH() && (isCollection() || isPropertyStream())) {
-        return false;
+        return methodNotAllowed(response, httpMethod(),
+            "collection properties are not supported for merge",
+            allowedMethods());
       }
-      return true;
+      
+      return ServiceRequest.assertHttpMethod(httpMethod(), allowedMethods(), response);
     }
 
     @Override
+    public HttpMethod[] allowedMethods() {
+      return new HttpMethod[] { HttpMethod.GET, HttpMethod.PUT,
+          HttpMethod.PATCH, HttpMethod.DELETE };
+    }
+    
+    @Override
     public ContentType getResponseContentType() throws ContentNegotiatorException {
       if (isPropertyComplex()) {
         return ContentNegotiator.doContentNegotiation(getUriInfo().getFormatOption(),
@@ -591,22 +632,31 @@ public class DataRequest extends ServiceRequest {
   class ValueRequest extends PropertyRequest {
 
     @Override
-    public boolean allowedMethod() {
+    public boolean assertHttpMethod(ODataResponse response)
+        throws ODataHandlerException {
       //part2-url-conventions # 4.7
       // Properties of type Edm.Stream already return the raw value of 
       // the media stream and do not support appending the $value segment.
       if (isPropertyStream() && isGET()) {
-        return false;
+        return methodNotAllowed(response, httpMethod(), "Edm.Stream properties do not support $value", 
+            allowedMethods());
       }
 
-      if ((isGET() || isDELETE() || isPropertyStream()) && getReturnRepresentation() != ReturnRepresentation.NONE) {
-        return false;
+      if ((isGET() || isDELETE() || isPropertyStream())
+          && getReturnRepresentation() != ReturnRepresentation.NONE) {
+        return methodNotAllowed(response, httpMethod(), "Invalid Prefer header used", 
+            allowedMethods());
       }
 
-      return isGET() || isDELETE() || isPUT();
+      return ServiceRequest.assertHttpMethod(httpMethod(), allowedMethods(), response);
     }
 
     @Override
+    public HttpMethod[] allowedMethods() {
+      return new HttpMethod[] { HttpMethod.GET, HttpMethod.PUT, HttpMethod.DELETE };
+    }
+    
+    @Override
     public ContentType getResponseContentType() throws ContentNegotiatorException {
       RepresentationType valueRepresentationType =
           uriResourceProperty.getType() == odata.createPrimitiveTypeInstance(EdmPrimitiveTypeKind.Binary) ?
@@ -651,10 +701,16 @@ public class DataRequest extends ServiceRequest {
   class SingletonRequest implements RequestType {
 
     @Override
-    public boolean allowedMethod() {
-      return isGET();
+    public boolean assertHttpMethod(ODataResponse response)
+        throws ODataHandlerException {
+      return ServiceRequest.assertHttpMethod(httpMethod(), allowedMethods(), response);
     }
-
+    
+    @Override
+    public HttpMethod[] allowedMethods() {
+      return new HttpMethod[] {HttpMethod.GET};
+    }
+    
     @Override
     public ContentType getResponseContentType() throws ContentNegotiatorException {
       return ContentNegotiator.doContentNegotiation(uriInfo.getFormatOption(), getODataRequest(),
@@ -685,8 +741,14 @@ public class DataRequest extends ServiceRequest {
     }
 
     @Override
-    public boolean allowedMethod() {
-      return isGET();
+    public boolean assertHttpMethod(ODataResponse response)
+        throws ODataHandlerException {
+      return ServiceRequest.assertHttpMethod(httpMethod(), allowedMethods(), response);
+    }
+    
+    @Override
+    public HttpMethod[] allowedMethods() {
+      return new HttpMethod[] {HttpMethod.GET};
     }
 
     @Override

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/9c61e223/lib/server-core-ext/src/main/java/org/apache/olingo/server/core/requests/FunctionRequest.java
----------------------------------------------------------------------
diff --git a/lib/server-core-ext/src/main/java/org/apache/olingo/server/core/requests/FunctionRequest.java b/lib/server-core-ext/src/main/java/org/apache/olingo/server/core/requests/FunctionRequest.java
index 94275ca..598199a 100644
--- a/lib/server-core-ext/src/main/java/org/apache/olingo/server/core/requests/FunctionRequest.java
+++ b/lib/server-core-ext/src/main/java/org/apache/olingo/server/core/requests/FunctionRequest.java
@@ -24,6 +24,7 @@ import java.util.List;
 import org.apache.olingo.commons.api.data.ContextURL;
 import org.apache.olingo.commons.api.edm.EdmFunction;
 import org.apache.olingo.commons.api.edm.EdmReturnType;
+import org.apache.olingo.commons.api.http.HttpMethod;
 import org.apache.olingo.server.api.OData;
 import org.apache.olingo.server.api.ODataApplicationException;
 import org.apache.olingo.server.api.ODataResponse;
@@ -33,7 +34,9 @@ import org.apache.olingo.server.api.serializer.PrimitiveSerializerOptions;
 import org.apache.olingo.server.api.uri.UriParameter;
 import org.apache.olingo.server.api.uri.UriResourceFunction;
 import org.apache.olingo.server.core.ContentNegotiatorException;
+import org.apache.olingo.server.core.ODataHandlerException;
 import org.apache.olingo.server.core.ServiceHandler;
+import org.apache.olingo.server.core.ServiceRequest;
 import org.apache.olingo.server.core.responses.EntityResponse;
 import org.apache.olingo.server.core.responses.EntitySetResponse;
 import org.apache.olingo.server.core.responses.PropertyResponse;
@@ -49,9 +52,8 @@ public class FunctionRequest extends OperationRequest {
   public void execute(ServiceHandler handler, ODataResponse response)
       throws ODataLibraryException, ODataApplicationException {
 
-    if (!allowedMethod()) {
-      methodNotAllowed();
-    }
+    // check for valid HTTP Verb
+    assertHttpMethod(response);
 
     // Functions always have return per 11.5.3
     if (isReturnTypePrimitive() || isReturnTypeComplex()) {
@@ -71,14 +73,25 @@ public class FunctionRequest extends OperationRequest {
   }
 
   @Override
-  public boolean allowedMethod() {
+  public boolean assertHttpMethod(ODataResponse response) throws ODataHandlerException {
     // look for discussion about composable functions in odata-discussion
     // group with thread "Clarification on "Function" invocations"
     if (getFunction().isComposable()) {
-      return (isGET() || isPATCH() || isDELETE() || isPOST() || isPUT());
+      boolean allowed =  (isGET() || isPATCH() || isDELETE() || isPOST() || isPUT());
+      if (!allowed) {
+        return methodNotAllowed(response,httpMethod(),
+            "Only composable functions are allowed PATCH, DELETE, POST and PUT methods",
+            allowedMethods());
+      }
     }
-    return isGET();
+    return ServiceRequest.assertHttpMethod(httpMethod(), allowedMethods(), response);
   }
+  
+  @Override
+  public HttpMethod[] allowedMethods() {
+    return new HttpMethod[] { HttpMethod.GET, HttpMethod.POST, HttpMethod.PUT,
+        HttpMethod.PATCH, HttpMethod.DELETE };
+  }  
 
   @SuppressWarnings("unchecked")
   @Override

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/9c61e223/lib/server-core-ext/src/main/java/org/apache/olingo/server/core/requests/MediaRequest.java
----------------------------------------------------------------------
diff --git a/lib/server-core-ext/src/main/java/org/apache/olingo/server/core/requests/MediaRequest.java b/lib/server-core-ext/src/main/java/org/apache/olingo/server/core/requests/MediaRequest.java
index b5626b5..f868d30 100644
--- a/lib/server-core-ext/src/main/java/org/apache/olingo/server/core/requests/MediaRequest.java
+++ b/lib/server-core-ext/src/main/java/org/apache/olingo/server/core/requests/MediaRequest.java
@@ -24,6 +24,7 @@ import java.util.List;
 import org.apache.olingo.commons.api.edm.EdmEntitySet;
 import org.apache.olingo.commons.api.edm.EdmEntityType;
 import org.apache.olingo.commons.api.format.ContentType;
+import org.apache.olingo.commons.api.http.HttpMethod;
 import org.apache.olingo.server.api.OData;
 import org.apache.olingo.server.api.ODataApplicationException;
 import org.apache.olingo.server.api.ODataResponse;
@@ -47,9 +48,10 @@ public class MediaRequest extends ServiceRequest {
   @Override
   public void execute(ServiceHandler handler, ODataResponse response)
       throws ODataLibraryException, ODataApplicationException {
-    if (!allowedMethod()) {
-      methodNotAllowed();
-    }
+    
+    // check for valid HTTP Verb
+    assertHttpMethod(response);
+    
     // POST will not be here, because the media is created as part of media
     // entity creation
     if (isGET()) {
@@ -91,9 +93,9 @@ public class MediaRequest extends ServiceRequest {
   private InputStream getMediaStream() {
     return this.request.getBody();
   }
-
+  
   @Override
-  public boolean allowedMethod() {
-    return isGET() || isPUT() || isDELETE();
-  }
+  public HttpMethod[] allowedMethods() {
+    return new HttpMethod[] { HttpMethod.GET, HttpMethod.PUT, HttpMethod.DELETE };
+  }   
 }

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/9c61e223/lib/server-core-ext/src/main/java/org/apache/olingo/server/core/requests/MetadataRequest.java
----------------------------------------------------------------------
diff --git a/lib/server-core-ext/src/main/java/org/apache/olingo/server/core/requests/MetadataRequest.java b/lib/server-core-ext/src/main/java/org/apache/olingo/server/core/requests/MetadataRequest.java
index f448942..ec38fa1 100644
--- a/lib/server-core-ext/src/main/java/org/apache/olingo/server/core/requests/MetadataRequest.java
+++ b/lib/server-core-ext/src/main/java/org/apache/olingo/server/core/requests/MetadataRequest.java
@@ -52,9 +52,8 @@ public class MetadataRequest extends ServiceRequest {
   public void execute(ServiceHandler handler, ODataResponse response)
       throws ODataLibraryException, ODataApplicationException {
 
-    if (!allowedMethod()) {
-      methodNotAllowed();
-    }
+    // check for valid HTTP Verb
+    assertHttpMethod(response);
 
     handler.readMetadata(this, MetadataResponse.getInstance(this, response));
   }

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/9c61e223/lib/server-core-ext/src/main/java/org/apache/olingo/server/core/requests/ServiceDocumentRequest.java
----------------------------------------------------------------------
diff --git a/lib/server-core-ext/src/main/java/org/apache/olingo/server/core/requests/ServiceDocumentRequest.java b/lib/server-core-ext/src/main/java/org/apache/olingo/server/core/requests/ServiceDocumentRequest.java
index c8f484d..805d859 100644
--- a/lib/server-core-ext/src/main/java/org/apache/olingo/server/core/requests/ServiceDocumentRequest.java
+++ b/lib/server-core-ext/src/main/java/org/apache/olingo/server/core/requests/ServiceDocumentRequest.java
@@ -48,9 +48,9 @@ public class ServiceDocumentRequest extends ServiceRequest {
   public void execute(ServiceHandler handler, ODataResponse response)
       throws ODataLibraryException, ODataApplicationException {
 
-    if (!allowedMethod()) {
-      methodNotAllowed();
-    }
+    // check for valid HTTP Verb
+    assertHttpMethod(response);
+    
     handler.readServiceDocument(this,
         ServiceDocumentResponse.getInstace(this, response, getResponseContentType()));
   }

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/9c61e223/lib/server-core-ext/src/test/java/org/apache/olingo/server/example/TripPinServiceTest.java
----------------------------------------------------------------------
diff --git a/lib/server-core-ext/src/test/java/org/apache/olingo/server/example/TripPinServiceTest.java b/lib/server-core-ext/src/test/java/org/apache/olingo/server/example/TripPinServiceTest.java
index 114a1f3..8bb4d5a 100644
--- a/lib/server-core-ext/src/test/java/org/apache/olingo/server/example/TripPinServiceTest.java
+++ b/lib/server-core-ext/src/test/java/org/apache/olingo/server/example/TripPinServiceTest.java
@@ -320,6 +320,14 @@ public class TripPinServiceTest {
     HttpResponse response = httpSend(request, 204);
     EntityUtils.consumeQuietly(response.getEntity());
   }
+  
+  @Test
+  public void testAllowHeader() throws Exception {
+    HttpResponse response = httpGET(baseURL + "/ResetDataSource", 405);
+    Header[] headers = response.getHeaders("Allow");
+    assertEquals("POST", headers[0].getValue());
+    EntityUtils.consumeQuietly(response.getEntity());
+  }  
 
   @Test @Ignore
   public void testFunctionImport() throws Exception {