Exception for URI /restconf/operations/module_name:rpc ended with slash 94/5394/4
authorJozef Gloncak <jgloncak@cisco.com>
Tue, 18 Feb 2014 13:05:44 +0000 (14:05 +0100)
committerGerrit Code Review <gerrit@opendaylight.org>
Mon, 24 Feb 2014 16:37:31 +0000 (16:37 +0000)
If URI of type /restconf/operations/module_name:rpc ends with slash
character (/) then exception with HTTP return code 404 and text
"Identifier IDENTIFIER_NAME can't contain slash character (/). If slash is
part of identifier name then use %2F placeholder."

Change-Id: Idbed90515280b414c10d28dc608faeee24986a29
Signed-off-by: Jozef Gloncak <jgloncak@cisco.com>
opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/rest/api/RestconfService.java
opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/restconf/impl/ControllerContext.xtend
opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/restconf/impl/RestconfImpl.xtend

index f6c39bf8c5a3ac70d75b8490f01aa2c5dfe73bc7..0683c45ebc82b7997a02cdbbceb90658a391fe5b 100644 (file)
@@ -94,14 +94,14 @@ public interface RestconfService {
     @Consumes({Draft02.MediaTypes.OPERATION+JSON, Draft02.MediaTypes.OPERATION+XML,
                Draft02.MediaTypes.DATA+JSON, Draft02.MediaTypes.DATA+XML,
                MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML, MediaType.TEXT_XML})
-    public StructuredData invokeRpc(@PathParam("identifier") String identifier, CompositeNode payload);
+    public StructuredData invokeRpc(@Encoded @PathParam("identifier") String identifier, CompositeNode payload);
     
     @POST
     @Path("/operations/{identifier:.+}")
     @Produces({Draft02.MediaTypes.OPERATION+JSON, Draft02.MediaTypes.OPERATION+XML,
                Draft02.MediaTypes.DATA+JSON, Draft02.MediaTypes.DATA+XML,
                MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML, MediaType.TEXT_XML})
-    public StructuredData invokeRpc(@PathParam("identifier") String identifier, @DefaultValue("") String noPayload);
+    public StructuredData invokeRpc(@Encoded @PathParam("identifier") String identifier, @DefaultValue("") String noPayload);
     
     @GET
     @Path("/config/{identifier:.+}")
index 482dcf8e8b37e5427c2470122bae9a15e3189a84..9b5c507811c18257f19abf7dacaf2452d849081e 100644 (file)
@@ -356,7 +356,6 @@ class ControllerContext implements SchemaServiceListener {
 
     private def toUriString(Object object) {
         if(object === null) return "";
-//        return object.toString.replace("/",URI_SLASH_PLACEHOLDER)
         return URLEncoder.encode(object.toString,URI_ENCODING_CHAR_SET)        
     }
     
@@ -620,6 +619,13 @@ class ControllerContext implements SchemaServiceListener {
             decodedPathArgs.add(URLDecoder.decode(pathArg, URI_ENCODING_CHAR_SET))
         }
         return decodedPathArgs
+    }
+
+    def urlPathArgDecode(String pathArg) {
+        if (pathArg !== null) {
+            return URLDecoder.decode(pathArg, URI_ENCODING_CHAR_SET)
+        }
+        return null
     }    
 
 }
index cfbce736fb70041ad2ee03eb26fdbc47d4c86797..e09dc7ac017d143c65f45564beeb1783ed97a8be 100644 (file)
@@ -230,10 +230,7 @@ class RestconfImpl implements RestconfService {
     }
 
     override invokeRpc(String identifier, CompositeNode payload) {
-        val rpc = identifier.rpcDefinition
-        if (rpc === null) {
-            throw new ResponseException(NOT_FOUND, "RPC does not exist.");
-        }
+        val rpc = resolveIdentifierInInvokeRpc(identifier)
         if (rpc.QName.namespace.toString == SAL_REMOTE_NAMESPACE && rpc.QName.localName == SAL_REMOTE_RPC_SUBSRCIBE) {
             val value = normalizeNode(payload, rpc.input, null)
             val pathNode = value?.getFirstSimpleByName(QName.create(rpc.QName, "path"))
@@ -267,7 +264,22 @@ class RestconfImpl implements RestconfService {
         if (!noPayload.nullOrEmpty) {
             throw new ResponseException(UNSUPPORTED_MEDIA_TYPE, "Content-Type contains unsupported Media Type.");
         }
-        return callRpc(identifier.rpcDefinition, null)
+        val rpc = resolveIdentifierInInvokeRpc(identifier)
+        return callRpc(rpc, null)
+    }
+
+    def resolveIdentifierInInvokeRpc(String identifier) {
+        if (identifier.indexOf("/") === -1) {
+            val identifierDecoded = identifier.urlPathArgDecode
+            val rpc = identifierDecoded.rpcDefinition
+            if (rpc !== null) {
+                return rpc
+            }
+            throw new ResponseException(NOT_FOUND, "RPC does not exist.");
+        }
+        val slashErrorMsg  = String.format("Identifier %n%s%ncan't contain slash character (/). +
+            If slash is part of identifier name then use %2F placeholder.",identifier)
+        throw new ResponseException(NOT_FOUND, slashErrorMsg);
     }
 
     private def StructuredData callRpc(RpcDefinition rpc, CompositeNode payload) {