diff --git a/Makefile b/Makefile index c59b46d..edac6ac 100644 --- a/Makefile +++ b/Makefile @@ -1,11 +1,13 @@ MS_PLUGIN_CURL_CORE = microservices/core MSI_CURL_GET_OBJ = microservices/msiCurlGetObj MSI_CURL_GET_STR = microservices/msiCurlGetStr +MSI_CURL_DELETE = microservices/msiCurlDelete MSI_CURL_POST = microservices/msiCurlPost +MSI_CURL_PUT = microservices/msiCurlPut MAKEFLAGS += --no-print-directory -LIBS = $(MS_PLUGIN_CURL_CORE) $(MSI_CURL_GET_OBJ) $(MSI_CURL_GET_STR) $(MSI_CURL_POST) +LIBS = $(MS_PLUGIN_CURL_CORE) $(MSI_CURL_GET_OBJ) $(MSI_CURL_GET_STR) $(MSI_CURL_DELETE) $(MSI_CURL_POST) $(MSI_CURL_PUT) .PHONY: all $(LIBS) clean all: $(LIBS) @@ -17,10 +19,16 @@ $(MSI_CURL_GET_OBJ): $(MS_PLUGIN_CURL_CORE) $(MSI_CURL_GET_STR): $(MS_PLUGIN_CURL_CORE) +$(MSI_CURL_DELETE): $(MS_PLUGIN_CURL_CORE) + $(MSI_CURL_POST): $(MS_PLUGIN_CURL_CORE) +$(MSI_CURL_PUT): $(MS_PLUGIN_CURL_CORE) + clean: @$(MAKE) -C $(MS_PLUGIN_CURL_CORE) clean; @$(MAKE) -C $(MSI_CURL_GET_OBJ) clean; @$(MAKE) -C $(MSI_CURL_GET_STR) clean; + @$(MAKE) -C $(MSI_CURL_DELETE) clean; @$(MAKE) -C $(MSI_CURL_POST) clean; + @$(MAKE) -C $(MSI_CURL_PUT) clean; diff --git a/microservices/core/include/irods_ms_plugin_curl.hpp b/microservices/core/include/irods_ms_plugin_curl.hpp index fd9d4f7..a37a054 100644 --- a/microservices/core/include/irods_ms_plugin_curl.hpp +++ b/microservices/core/include/irods_ms_plugin_curl.hpp @@ -34,6 +34,7 @@ #define IRODS_CURL_DATA_KW "data" #define IRODS_CURL_HEADERS_KW "headers" +#define IRODS_CURL_TIMEOUT_MS_KW "timeout" // Input struct for curl write callback function. // Does not go over the wire as far as iRODS is concerned. @@ -77,8 +78,11 @@ class irodsCurl { irods::error get_str( char*, char** ); - irods::error post( char*, keyValPair_t*, char** ); + irods::error del( char*, keyValPair_t*, char** ); + + irods::error put( char*, keyValPair_t*, keyValPair_t*, char** ); + irods::error post( char*, keyValPair_t*, char** ); // Callback progress function for the curl handler static int progress( void*, double, double, double, double ); diff --git a/microservices/core/src/irods_ms_plugin_curl.cpp b/microservices/core/src/irods_ms_plugin_curl.cpp index c94cf4c..86ede8b 100644 --- a/microservices/core/src/irods_ms_plugin_curl.cpp +++ b/microservices/core/src/irods_ms_plugin_curl.cpp @@ -93,6 +93,47 @@ irods::error irodsCurl::get_obj( char *url, keyValPair_t* options, size_t *trans return SUCCESS(); } +irods::error irodsCurl::del( char *url, keyValPair_t* curl_options, char **buffer ) { + CURLcode res = CURLE_OK; + string_t string; + curlProgress_t prog; // for progress and cutoff + + // Destination string_t init + string.ptr = strdup(""); + string.len = 0; + + // Progress struct init + prog.downloaded = 0; + prog.cutoff = 0; + + // Set up easy handler + curl_easy_setopt( curl, CURLOPT_USERAGENT, "libcurl-agent/1.0"); + curl_easy_setopt( curl, CURLOPT_WRITEFUNCTION, &irodsCurl::write_str ); + curl_easy_setopt( curl, CURLOPT_WRITEDATA, &string ); + curl_easy_setopt( curl, CURLOPT_URL, url ); + curl_easy_setopt( curl, CURLOPT_CUSTOMREQUEST, "DELETE"); + + // Set up curl timeout + char* timeout_s = NULL; + timeout_s = getValByKey( curl_options, IRODS_CURL_TIMEOUT_MS_KW ); + if ( timeout_s && strlen(timeout_s)) { + curl_easy_setopt( curl, CURLOPT_TIMEOUT_MS, atol(timeout_s)); + } + + // CURL call + res = curl_easy_perform( curl ); + + // Output + *buffer = string.ptr; + + // Error logging + if ( res != CURLE_OK ) { + rodsLog( LOG_ERROR, "irodsCurl::delete: cURL error: %s", curl_easy_strerror( res ) ); + return CODE(PLUGIN_ERROR); + } + + return SUCCESS(); +} irods::error irodsCurl::get_str( char *url, char **buffer ) { CURLcode res = CURLE_OK; @@ -134,6 +175,63 @@ irods::error irodsCurl::get_str( char *url, char **buffer ) { return SUCCESS(); } +irods::error irodsCurl::put( char *url, keyValPair_t *post_fields, keyValPair_t *curl_options, char **response ) { + CURLcode res = CURLE_OK; + + char *headers, *data; // input + char *encoded_data = NULL; + + struct curl_slist *header_list = NULL; + + string_t string; // server response + int must_encode = 0; // for the time being... + + // Parse POST fields + data = getValByKey(post_fields, IRODS_CURL_DATA_KW); + headers = getValByKey(post_fields, IRODS_CURL_HEADERS_KW); + + // Init string + string.ptr = strdup(""); + string.len = 0; + + // url-encode data + if (must_encode && data) { + encoded_data = curl_easy_escape(curl, data, 0); + } + + // Set headers + if (headers && strlen(headers)) { + header_list = curl_slist_append(header_list, headers); + curl_easy_setopt(curl, CURLOPT_HTTPHEADER, header_list); + } + + // Set up easy handler + curl_easy_setopt(curl, CURLOPT_URL, url); + curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, "PUT"); + curl_easy_setopt(curl, CURLOPT_POSTFIELDS, data); + curl_easy_setopt(curl, CURLOPT_USERAGENT, "libcurl-agent/1.0"); + curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, &irodsCurl::write_str); + curl_easy_setopt(curl, CURLOPT_WRITEDATA, &string); + + // Set up curl timeout + char* timeout_s = NULL; + timeout_s = getValByKey( curl_options, IRODS_CURL_TIMEOUT_MS_KW ); + if ( timeout_s && strlen(timeout_s)) { + curl_easy_setopt( curl, CURLOPT_TIMEOUT_MS, atol(timeout_s)); + } + + // CURL call + res = curl_easy_perform(curl); + + // Cleanup + if (header_list) curl_slist_free_all(header_list); + if (encoded_data) curl_free(encoded_data); + + // Output + *response = string.ptr; + + return CODE(res); +} irods::error irodsCurl::post( char *url, keyValPair_t *post_fields, char **response ) { CURLcode res = CURLE_OK; diff --git a/microservices/msiCurlDelete/Makefile b/microservices/msiCurlDelete/Makefile new file mode 100644 index 0000000..c5d9a98 --- /dev/null +++ b/microservices/msiCurlDelete/Makefile @@ -0,0 +1,14 @@ +GCC = g++ + +INC_DIR = ../core/include +OBJ_DIR = ../core/obj + +INC=-I/usr/include/irods/ -I/usr/include/irods/boost/ -I${INC_DIR} + +all: libmsiCurlDelete + +libmsiCurlDelete: + ${GCC} ${INC} -DRODS_SERVER -fPIC -shared -g -Wno-deprecated -o $@.so $@.cpp ${OBJ_DIR}/irods_ms_plugin_curl.o `curl-config --libs` /usr/lib/libirods_client.a + +clean: + @rm -f ./*.so diff --git a/microservices/msiCurlDelete/libmsiCurlDelete.cpp b/microservices/msiCurlDelete/libmsiCurlDelete.cpp new file mode 100644 index 0000000..9a369f7 --- /dev/null +++ b/microservices/msiCurlDelete/libmsiCurlDelete.cpp @@ -0,0 +1,32 @@ +/* + * libmsiCurlDelete.cpp + * + * Created on: June 1, 2017 + * Author: Hurng-Chun Lee + */ + + +// =-=-=-=-=-=-=- +#include "irods_ms_plugin_curl.hpp" + + +// =-=-=-=-=-=-=- +// New microservice plugin definition style +MICROSERVICE_BEGIN( + msiCurlDelete, + STR, url, INPUT, + KeyValPair, curl_options, INPUT, + STR, buffer, OUTPUT PTR NO_ALLOC ) + + irods::error res = SUCCESS(); + + // Create irodsCurl instance + irodsCurl myCurl( rei->rsComm ); + + // Call irodsCurl::get_str + res = myCurl.del( url, &curl_options, &buffer ); + + // Done + RETURN ( res.code()); + +MICROSERVICE_END diff --git a/microservices/msiCurlPost/libmsiCurlPost.cpp b/microservices/msiCurlPost/libmsiCurlPost.cpp index 03709f4..f5e9e2c 100644 --- a/microservices/msiCurlPost/libmsiCurlPost.cpp +++ b/microservices/msiCurlPost/libmsiCurlPost.cpp @@ -1,15 +1,14 @@ /* * libmsiCurlPost.cpp * - * Created on: May 27, 2014 - * Author: adt + * Created on: June 1, 2017 + * Author: Hurng-Chun Lee */ // =-=-=-=-=-=-=- #include "irods_ms_plugin_curl.hpp" - // =-=-=-=-=-=-=- // New microservice plugin definition style MICROSERVICE_BEGIN( diff --git a/microservices/msiCurlPut/Makefile b/microservices/msiCurlPut/Makefile new file mode 100644 index 0000000..ca5c1dc --- /dev/null +++ b/microservices/msiCurlPut/Makefile @@ -0,0 +1,14 @@ +GCC = g++ + +INC_DIR = ../core/include +OBJ_DIR = ../core/obj + +INC=-I/usr/include/irods/ -I/usr/include/irods/boost/ -I${INC_DIR} + +all: libmsiCurlPut + +libmsiCurlPut: + ${GCC} ${INC} -DRODS_SERVER -fPIC -shared -g -Wno-deprecated -o $@.so $@.cpp ${OBJ_DIR}/irods_ms_plugin_curl.o `curl-config --libs` /usr/lib/libirods_client.a + +clean: + @rm -f ./*.so diff --git a/microservices/msiCurlPut/libmsiCurlPut.cpp b/microservices/msiCurlPut/libmsiCurlPut.cpp new file mode 100644 index 0000000..7f09e63 --- /dev/null +++ b/microservices/msiCurlPut/libmsiCurlPut.cpp @@ -0,0 +1,34 @@ +/* + * libmsiCurlPut.cpp + * + * Created on: May 27, 2014 + * Author: adt + */ + + +// =-=-=-=-=-=-=- +#include "irods_ms_plugin_curl.hpp" + + +// =-=-=-=-=-=-=- +// New microservice plugin definition style +MICROSERVICE_BEGIN( + msiCurlPut, + STR, url, INPUT, + KeyValPair, post_fields, INPUT, + KeyValPair, curl_options, INPUT, + STR, response, OUTPUT PTR NO_ALLOC ) + + irods::error res = SUCCESS(); + + // Create irodsCurl instance + irodsCurl myCurl( rei->rsComm ); + + // Call irodsCurl::post + res = myCurl.put( url, &post_fields, &curl_options, &response ); + + // Done + RETURN ( res.code()); + +MICROSERVICE_END + diff --git a/packaging/irods_microservice_plugins_curl.list.template b/packaging/irods_microservice_plugins_curl.list.template index 4532c0b..e303435 100644 --- a/packaging/irods_microservice_plugins_curl.list.template +++ b/packaging/irods_microservice_plugins_curl.list.template @@ -52,10 +52,14 @@ END_PREINSTALL . /etc/irods/service_account.config 2> /dev/null chown $$IRODS_SERVICE_ACCOUNT_NAME:$$IRODS_SERVICE_GROUP_NAME ${IRODS_HOME_DIR}/iRODS/clients/icommands/test/rules3.0/curlGetObj.r chown $$IRODS_SERVICE_ACCOUNT_NAME:$$IRODS_SERVICE_GROUP_NAME ${IRODS_HOME_DIR}/iRODS/clients/icommands/test/rules3.0/curlGetStr.r +chown $$IRODS_SERVICE_ACCOUNT_NAME:$$IRODS_SERVICE_GROUP_NAME ${IRODS_HOME_DIR}/iRODS/clients/icommands/test/rules3.0/curlDelete.r chown $$IRODS_SERVICE_ACCOUNT_NAME:$$IRODS_SERVICE_GROUP_NAME ${IRODS_HOME_DIR}/iRODS/clients/icommands/test/rules3.0/curlPost.r +chown $$IRODS_SERVICE_ACCOUNT_NAME:$$IRODS_SERVICE_GROUP_NAME ${IRODS_HOME_DIR}/iRODS/clients/icommands/test/rules3.0/curlPut.r chown $$IRODS_SERVICE_ACCOUNT_NAME:$$IRODS_SERVICE_GROUP_NAME ${IRODS_HOME_DIR}/plugins/microservices/libmsiCurlGetObj.so chown $$IRODS_SERVICE_ACCOUNT_NAME:$$IRODS_SERVICE_GROUP_NAME ${IRODS_HOME_DIR}/plugins/microservices/libmsiCurlGetStr.so +chown $$IRODS_SERVICE_ACCOUNT_NAME:$$IRODS_SERVICE_GROUP_NAME ${IRODS_HOME_DIR}/plugins/microservices/libmsiCurlDelete.so chown $$IRODS_SERVICE_ACCOUNT_NAME:$$IRODS_SERVICE_GROUP_NAME ${IRODS_HOME_DIR}/plugins/microservices/libmsiCurlPost.so +chown $$IRODS_SERVICE_ACCOUNT_NAME:$$IRODS_SERVICE_GROUP_NAME ${IRODS_HOME_DIR}/plugins/microservices/libmsiCurlPut.so chown $$IRODS_SERVICE_ACCOUNT_NAME:$$IRODS_SERVICE_GROUP_NAME ${IRODS_HOME_DIR}/tests/pydevtest/test_irods_microservice_plugins_curl.py END_POSTINSTALL @@ -100,8 +104,12 @@ END_POSTREMOVE # =-=-=-=-=-=-=- f 644 root root ${IRODS_HOME_DIR}/iRODS/clients/icommands/test/rules3.0/curlGetObj.r rules/curlGetObj.r f 644 root root ${IRODS_HOME_DIR}/iRODS/clients/icommands/test/rules3.0/curlGetStr.r rules/curlGetStr.r +f 644 root root ${IRODS_HOME_DIR}/iRODS/clients/icommands/test/rules3.0/curlDelete.r rules/curlDelete.r f 644 root root ${IRODS_HOME_DIR}/iRODS/clients/icommands/test/rules3.0/curlPost.r rules/curlPost.r +f 644 root root ${IRODS_HOME_DIR}/iRODS/clients/icommands/test/rules3.0/curlPut.r rules/curlPut.r f 644 root root ${IRODS_HOME_DIR}/plugins/microservices/libmsiCurlGetObj.so microservices/msiCurlGetObj/libmsiCurlGetObj.so f 644 root root ${IRODS_HOME_DIR}/plugins/microservices/libmsiCurlGetStr.so microservices/msiCurlGetStr/libmsiCurlGetStr.so +f 644 root root ${IRODS_HOME_DIR}/plugins/microservices/libmsiCurlDelete.so microservices/msiCurlDelete/libmsiCurlDelete.so f 644 root root ${IRODS_HOME_DIR}/plugins/microservices/libmsiCurlPost.so microservices/msiCurlPost/libmsiCurlPost.so +f 644 root root ${IRODS_HOME_DIR}/plugins/microservices/libmsiCurlPut.so microservices/msiCurlPut/libmsiCurlPut.so f 644 root root ${IRODS_HOME_DIR}/tests/pydevtest/test_irods_microservice_plugins_curl.py packaging/test_irods_microservice_plugins_curl.py diff --git a/packaging/test_irods_microservice_plugins_curl.py b/packaging/test_irods_microservice_plugins_curl.py index c88ce91..b046c95 100644 --- a/packaging/test_irods_microservice_plugins_curl.py +++ b/packaging/test_irods_microservice_plugins_curl.py @@ -32,3 +32,10 @@ def test_curl_post(self): # will have to dynamically pass form_data to the rule once that's fixed form_data = 'Sent from iRODS' self.admin_sessions[0].assert_icommand(['irule', '-F', rule_file], 'STDOUT_SINGLELINE', form_data) + + def test_curl_put(self): + rule_file = os.path.join(self.rules_dir, 'curlPut.r') + + # will have to dynamically pass form_data to the rule once that's fixed + form_data = 'Sent from iRODS' + self.admin_sessions[0].assert_icommand(['irule', '-F', rule_file], 'STDOUT_SINGLELINE', form_data) diff --git a/rules/curlDelete.r b/rules/curlDelete.r new file mode 100644 index 0000000..1a49970 --- /dev/null +++ b/rules/curlDelete.r @@ -0,0 +1,7 @@ +curlDelete { +*options.'timeout' = '1000'; +msiCurlDelete(*url, *options, *outStr); +writeLine("stdout", *outStr); +} +INPUT *url=$"http://www.textfiles.com/art/dragon.txt" +OUTPUT ruleExecOut diff --git a/rules/curlPut.r b/rules/curlPut.r new file mode 100644 index 0000000..98f5268 --- /dev/null +++ b/rules/curlPut.r @@ -0,0 +1,9 @@ +curlPut { +*postFields."data" = *data; +*options."timeout" = '1000'; +msiCurlPut(*url, *postFields, *options, *response); +writeLine("stdout", "server response: "++*response); +} +INPUT *url=$"http://httpbin.org/post",*data="Sent from iRODS" +OUTPUT ruleExecOut +# See also http://requestb.in/ for quick testing of POST requests