From b3feab875d67888ca2310a900eb806556b744c7f Mon Sep 17 00:00:00 2001 From: Shrikant Sharat Kandula Date: Tue, 30 Jun 2020 19:29:38 +0530 Subject: [PATCH] Give appropriate error when method is invalid in cURL command --- .../server/exceptions/AppsmithError.java | 1 + .../server/services/CurlImporterService.java | 31 ++++++++++++----- .../services/CurlImporterServiceTest.java | 33 ++++++++++--------- 3 files changed, 40 insertions(+), 25 deletions(-) diff --git a/app/server/appsmith-server/src/main/java/com/appsmith/server/exceptions/AppsmithError.java b/app/server/appsmith-server/src/main/java/com/appsmith/server/exceptions/AppsmithError.java index 856a5c803bef..7c4fa355d126 100644 --- a/app/server/appsmith-server/src/main/java/com/appsmith/server/exceptions/AppsmithError.java +++ b/app/server/appsmith-server/src/main/java/com/appsmith/server/exceptions/AppsmithError.java @@ -48,6 +48,7 @@ public enum AppsmithError { MARKETPLACE_TIMEOUT(504, 5041, "Marketplace is responding too slowly. Please try again later"), DATASOURCE_HAS_ACTIONS(409, 4030, "Cannot delete datasource since it has {0} action(s) using it."), ORGANIZATION_ID_NOT_GIVEN(400, 4031, "Missing organization id. Please enter one."), + INVALID_CURL_METHOD(400, 4032, "Invalid method in cURL command: {0}."), ; diff --git a/app/server/appsmith-server/src/main/java/com/appsmith/server/services/CurlImporterService.java b/app/server/appsmith-server/src/main/java/com/appsmith/server/services/CurlImporterService.java index 38c5c614b7fc..9ab5c709182f 100644 --- a/app/server/appsmith-server/src/main/java/com/appsmith/server/services/CurlImporterService.java +++ b/app/server/appsmith-server/src/main/java/com/appsmith/server/services/CurlImporterService.java @@ -5,6 +5,7 @@ import com.appsmith.external.models.Property; import com.appsmith.server.domains.Action; import com.appsmith.server.domains.Datasource; +import com.appsmith.server.domains.Plugin; import com.appsmith.server.exceptions.AppsmithError; import com.appsmith.server.exceptions.AppsmithException; import lombok.extern.slf4j.Slf4j; @@ -48,7 +49,13 @@ public CurlImporterService(ActionService actionService, PluginService pluginServ @Override public Mono importAction(Object input, String pageId, String name, String orgId) { - Action action = curlToAction((String) input, pageId, name); + Action action; + + try { + action = curlToAction((String) input, pageId, name); + } catch (AppsmithException e) { + return Mono.error(e); + } if (action == null) { return Mono.error(new AppsmithException(AppsmithError.INVALID_CURL_COMMAND)); @@ -56,19 +63,21 @@ public Mono importAction(Object input, String pageId, String name, Strin // Set the default values for datasource (plugin, name) and then create the action // with embedded datasource - return pluginService.findByPackageName(RESTAPI_PLUGIN) - .flatMap(plugin -> { - final Datasource datasource = action.getDatasource(); + return Mono.zip(Mono.just(action), pluginService.findByPackageName(RESTAPI_PLUGIN)) + .flatMap(tuple -> { + final Action action1 = tuple.getT1(); + final Plugin plugin = tuple.getT2(); + final Datasource datasource = action1.getDatasource(); final DatasourceConfiguration datasourceConfiguration = datasource.getDatasourceConfiguration(); datasource.setName(datasourceConfiguration.getUrl()); datasource.setPluginId(plugin.getId()); datasource.setOrganizationId(orgId); - return Mono.just(action); + return Mono.just(action1); }) .flatMap(actionService::create); } - public Action curlToAction(String command, String pageId, String name) { + public Action curlToAction(String command, String pageId, String name) throws AppsmithException { Action action = curlToAction(command); if (action != null) { action.setPageId(pageId); @@ -77,7 +86,7 @@ public Action curlToAction(String command, String pageId, String name) { return action; } - public Action curlToAction(String command) { + public Action curlToAction(String command) throws AppsmithException { // Three stages of parsing the cURL command: // 1. lex: Split the string into tokens, respecting the quoting semantics of a POSIX-compliant shell. // 2. normalize: Normalize all the command line arguments of a curl command, into their long-form versions. @@ -238,7 +247,7 @@ public List normalize(List tokens) { return normalizedTokens; } - public Action parse(List tokens) { + public Action parse(List tokens) throws AppsmithException { // Curl argument parsing as per . if (!"curl".equals(tokens.get(0))) { @@ -267,7 +276,11 @@ public Action parse(List tokens) { if (ARG_REQUEST.equals(state)) { // The `token` is next to `--request`. - actionConfiguration.setHttpMethod(HttpMethod.valueOf(token.toUpperCase())); + final HttpMethod method = HttpMethod.resolve(token.toUpperCase()); + if (method == null) { + throw new AppsmithException(AppsmithError.INVALID_CURL_METHOD, token); + } + actionConfiguration.setHttpMethod(method); } else if (ARG_HEADER.equals(state)) { // The `token` is next to `--header`. diff --git a/app/server/appsmith-server/src/test/java/com/appsmith/server/services/CurlImporterServiceTest.java b/app/server/appsmith-server/src/test/java/com/appsmith/server/services/CurlImporterServiceTest.java index f9bb7b422ee7..192142096192 100644 --- a/app/server/appsmith-server/src/test/java/com/appsmith/server/services/CurlImporterServiceTest.java +++ b/app/server/appsmith-server/src/test/java/com/appsmith/server/services/CurlImporterServiceTest.java @@ -8,6 +8,7 @@ import com.appsmith.server.domains.Application; import com.appsmith.server.domains.Page; import com.appsmith.server.domains.User; +import com.appsmith.server.exceptions.AppsmithException; import lombok.extern.slf4j.Slf4j; import org.junit.Before; import org.junit.Test; @@ -130,7 +131,7 @@ public void importValidCurlCommand() { } @Test - public void urlInSingleQuotes() { + public void urlInSingleQuotes() throws AppsmithException { String command = "curl --location --request POST 'http://localhost:8080/scrap/api?slugifiedName=Freshdesk&ownerName=volodimir.kudriachenko'"; Action action = curlImporterService.curlToAction(command); @@ -148,7 +149,7 @@ public void urlInSingleQuotes() { } @Test - public void missingMethod() { + public void missingMethod() throws AppsmithException { String command = "curl http://localhost:8080/scrap/api"; Action action = curlImporterService.curlToAction(command); @@ -166,7 +167,7 @@ public void missingMethod() { } @Test - public void multilineCommand() { + public void multilineCommand() throws AppsmithException { String command = "curl -d '{\"message\": \"The force is strong with this one...\"}' \\\n" + " -H \"Content-Type: application/json\" \\\n" + " \"http://piper.net\""; @@ -187,7 +188,7 @@ public void multilineCommand() { } @Test - public void testUrlEncodedData() { + public void testUrlEncodedData() throws AppsmithException { Action action = curlImporterService.curlToAction( "curl --data-urlencode '=all of this exactly, but url encoded ' http://loc" ); @@ -211,7 +212,7 @@ public void testUrlEncodedData() { } @Test - public void chromeCurlCommands1() { + public void chromeCurlCommands1() throws AppsmithException { Action action = curlImporterService.curlToAction( "curl 'http://localhost:3000/applications/5ea054c531cc0f7a61af0cbe/pages/5ea054c531cc0f7a61af0cc0/edit/api' \\\n" + " -H 'Connection: keep-alive' \\\n" + @@ -276,7 +277,7 @@ public void chromeCurlCommands1() { } @Test - public void firefoxCurlCommands1() { + public void firefoxCurlCommands1() throws AppsmithException { final Action action = curlImporterService.curlToAction("curl 'http://localhost:8080/api/v1/actions?applicationId=5ea054c531cc0f7a61af0cbe' -H 'User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:75.0) Gecko/20100101 Firefox/75.0' -H 'Accept: application/json, text/plain, */*' -H 'Accept-Language: en-US,en;q=0.5' --compressed -H 'Origin: http://localhost:3000' -H 'DNT: 1' -H 'Connection: keep-alive' -H 'Referer: http://localhost:3000/' -H 'Cookie: SESSION=69b4b392-03b6-4e0a-a889-49ca4b8e267e'"); assertMethod(action, HttpMethod.GET); assertUrl(action, "http://localhost:8080"); @@ -295,7 +296,7 @@ public void firefoxCurlCommands1() { } @Test - public void postmanExportCommands1() { + public void postmanExportCommands1() throws AppsmithException { final Action action = curlImporterService.curlToAction( "curl --location --request PUT 'https://release-api.appsmith.com/api/v1/users/5d81feb218e1c8217d20e13f' \\\n" + "--header 'Content-Type: application/json' \\\n" + @@ -319,7 +320,7 @@ public void postmanExportCommands1() { } @Test - public void postmanCreateDatasource() { + public void postmanCreateDatasource() throws AppsmithException { final Action action = curlImporterService.curlToAction( "curl --location --request POST 'https://release-api.appsmith.com/api/v1/datasources' \\\n" + "--header 'Content-Type: application/json' \\\n" + @@ -361,7 +362,7 @@ public void postmanCreateDatasource() { } @Test - public void postmanCreateProvider() { + public void postmanCreateProvider() throws AppsmithException { final Action action = curlImporterService.curlToAction( "curl --location --request POST 'https://release-api.appsmith.com/api/v1/providers' \\\n" + "--header 'Cookie: SESSION=61ee9df5-3cab-400c-831b-9533218d8f9f' \\\n" + @@ -429,7 +430,7 @@ public void postmanCreateProvider() { } @Test - public void parseCurlJsTestsPart1() { + public void parseCurlJsTestsPart1() throws AppsmithException { // Tests adapted from . Action action = curlImporterService.curlToAction("curl http://api.sloths.com"); @@ -470,7 +471,7 @@ public void parseCurlJsTestsPart1() { } @Test - public void parseCurlJsTestsPart2() { + public void parseCurlJsTestsPart2() throws AppsmithException { Action action = curlImporterService.curlToAction("curl -d \"foo=bar\" https://api.sloths.com"); assertMethod(action, HttpMethod.POST); assertUrl(action, "https://api.sloths.com"); @@ -538,7 +539,7 @@ public void parseCurlJsTestsPart2() { } @Test - public void parseWithoutProtocol() { + public void parseWithoutProtocol() throws AppsmithException { Action action = curlImporterService.curlToAction("curl api.sloths.com"); assertMethod(action, HttpMethod.GET); assertUrl(action, "http://api.sloths.com"); @@ -548,7 +549,7 @@ public void parseWithoutProtocol() { } @Test - public void parseWithDashedUrlArgument() { + public void parseWithDashedUrlArgument() throws AppsmithException { Action action = curlImporterService.curlToAction("curl --url http://api.sloths.com"); assertMethod(action, HttpMethod.GET); assertUrl(action, "http://api.sloths.com"); @@ -558,7 +559,7 @@ public void parseWithDashedUrlArgument() { } @Test - public void parseWithDashedUrlArgument2() { + public void parseWithDashedUrlArgument2() throws AppsmithException { Action action = curlImporterService.curlToAction("curl -X POST -d '{\"name\":\"test\",\"salary\":\"123\",\"age\":\"23\"}' --url http://dummy.restapiexample.com/api/v1/create"); assertMethod(action, HttpMethod.POST); assertUrl(action, "http://dummy.restapiexample.com"); @@ -568,7 +569,7 @@ public void parseWithDashedUrlArgument2() { } @Test - public void parseWithSpacedHeader() { + public void parseWithSpacedHeader() throws AppsmithException { Action action = curlImporterService.curlToAction("curl -H \"Accept:application/json\" http://httpbin.org/get"); assertMethod(action, HttpMethod.GET); assertUrl(action, "http://httpbin.org"); @@ -578,7 +579,7 @@ public void parseWithSpacedHeader() { } @Test - public void parseCurlCommand1() { + public void parseCurlCommand1() throws AppsmithException { Action action = curlImporterService.curlToAction("curl -i -H \"Accept: application/json\" -H \"Content-Type: application/json\" -X POST -d '{\"name\":\"test\",\"salary\":\"123\",\"age\":\"23\"}' --url http://dummy.restapiexample.com/api/v1/create"); assertMethod(action, HttpMethod.POST); assertUrl(action, "http://dummy.restapiexample.com");