From 3c8207e85c69993a9795e08979fa7cddbafcf165 Mon Sep 17 00:00:00 2001 From: Matthieu Le Guellaut Date: Thu, 10 May 2018 11:08:40 -0400 Subject: [PATCH] Added HTTP METHODS to CurlHTTPRequest Signed-off-by: Matthieu Le Guellaut --- lib/curl/curl.nit | 151 +++++++++++++++++++++++++++++++-------- lib/curl/examples/curl_rest.nit | 43 +++++++++++ 2 files changed, 164 insertions(+), 30 deletions(-) create mode 100644 lib/curl/examples/curl_rest.nit diff --git a/lib/curl/curl.nit b/lib/curl/curl.nit index 64fbff2..34b2576 100644 --- a/lib/curl/curl.nit +++ b/lib/curl/curl.nit @@ -122,71 +122,158 @@ class CurlHTTPRequest # instead of a TCP connection and DNS hostname resolution. var unix_socket_path: nullable String is writable + # The HTTP method, GET by default + # + # Must be a capitalized string with request name complying with RFC7231 + var method: String = "GET" is optional, writable + # Execute HTTP request # # By default, the response body is returned in an instance of `CurlResponse`. # This behavior can be customized by setting a custom `delegate`. fun execute: CurlResponse do + # Reset libcurl parameters as the lib is shared and options + # might affect requests from one another. + self.curl.native = new NativeCurl.easy_init if not self.curl.is_ok then return answer_failure(0, "Curl instance is not correctly initialized") var success_response = new CurlResponseSuccess var callback_receiver: CurlCallbacks = success_response - if self.delegate != null then callback_receiver = self.delegate.as(not null) + var err : CURLCode + + # Prepare request + err = prepare_request(callback_receiver) + if not err.is_ok then return answer_failure(err.to_i, err.to_s) + + # Perform request + var err_resp = perform + if err_resp != null then return err_resp + + var st_code = self.curl.native.easy_getinfo_long(new CURLInfoLong.response_code) + if not st_code == null then success_response.status_code = st_code + self.curl.native.easy_clean + + return success_response + end + + # Internal function that sets cURL options and request' parameters + private fun prepare_request(callback_receiver: CurlCallbacks) : CURLCode + do + var err + + # cURL options and delegates + err = set_curl_options + if not err.is_ok then return err + + # Callbacks + err = set_curl_callback(callback_receiver) + if not err.is_ok then return err + + # HTTP Header + err = set_curl_http_header + if not err.is_ok then return err + + # Set HTTP method and body + err = set_method + if not err.is_ok then return err + err = set_body + + return err + end + + # Set cURL parameters according to assigned HTTP method set in method + # attribute and body if the method allows it according to RFC7231 + private fun set_method : CURLCode + do + var err : CURLCode + + if self.method=="GET" then + err=self.curl.native.easy_setopt(new CURLOption.get, 1) + + else if self.method=="POST" then + err=self.curl.native.easy_setopt(new CURLOption.post, 1) + + else if self.method=="HEAD" then + err=self.curl.native.easy_setopt(new CURLOption.no_body,1) + + else + err=self.curl.native.easy_setopt(new CURLOption.custom_request,self.method) + end + return err + end + + # Set request's body + private fun set_body : CURLCode + do + var err + var data = self.data + var body = self.body + + if data != null then + var postdatas = data.to_url_encoded(self.curl) + err = self.curl.native.easy_setopt(new CURLOption.postfields, postdatas) + if not err.is_ok then return err + else if body != null then + err = self.curl.native.easy_setopt(new CURLOption.postfields, body) + if not err.is_ok then return err + end + return new CURLCode.ok + end + + # Set cURL options + # such as delegate, follow location, URL, user agent and address family + private fun set_curl_options : CURLCode + do var err err = self.curl.native.easy_setopt(new CURLOption.follow_location, 1) - if not err.is_ok then return answer_failure(err.to_i, err.to_s) + if not err.is_ok then return err err = self.curl.native.easy_setopt(new CURLOption.url, url) - if not err.is_ok then return answer_failure(err.to_i, err.to_s) + if not err.is_ok then return err var user_agent = user_agent if user_agent != null then err = curl.native.easy_setopt(new CURLOption.user_agent, user_agent) - if not err.is_ok then return answer_failure(err.to_i, err.to_s) + if not err.is_ok then return err end var unix_socket_path = unix_socket_path if unix_socket_path != null then err = self.curl.native.easy_setopt(new CURLOption.unix_socket_path, unix_socket_path) - if not err.is_ok then return answer_failure(err.to_i, err.to_s) + if not err.is_ok then return err end + return err + end + + # Set cURL callback + private fun set_curl_callback(callback_receiver : CurlCallbacks) : CURLCode + do + var err + + if self.delegate != null then callback_receiver = self.delegate.as(not null) - # Callbacks err = self.curl.native.register_callback_header(callback_receiver) - if not err.is_ok then return answer_failure(err.to_i, err.to_s) + if not err.is_ok then return err err = self.curl.native.register_callback_body(callback_receiver) - if not err.is_ok then return answer_failure(err.to_i, err.to_s) + if not err.is_ok then return err - # HTTP Header + return err + end + + # Set cURL request header according to attribute headers + private fun set_curl_http_header : CURLCode + do var headers = self.headers if headers != null then var headers_joined = headers.join_pairs(": ") - err = self.curl.native.easy_setopt(new CURLOption.httpheader, headers_joined.to_curlslist) - if not err.is_ok then return answer_failure(err.to_i, err.to_s) - end - - # Datas - var data = self.data - if data != null then - var postdatas = data.to_url_encoded(self.curl) - err = self.curl.native.easy_setopt(new CURLOption.postfields, postdatas) - if not err.is_ok then return answer_failure(err.to_i, err.to_s) - else if body != null then - err = self.curl.native.easy_setopt(new CURLOption.postfields, body.as(not null)) - if not err.is_ok then return answer_failure(err.to_i, err.to_s) + var err = self.curl.native.easy_setopt(new CURLOption.httpheader, headers_joined.to_curlslist) + if not err.is_ok then return err end - - var err_resp = perform - if err_resp != null then return err_resp - - var st_code = self.curl.native.easy_getinfo_long(new CURLInfoLong.response_code) - if not st_code == null then success_response.status_code = st_code - - return success_response + return new CURLCode.ok end # Download to file given resource @@ -246,6 +333,7 @@ class CurlHTTPRequest end end + # CURL Mail Request # # ~~~ @@ -359,6 +447,7 @@ class CurlMail # Execute Mail request with settings configured through attribute fun execute: nullable CurlResponseFailed do + self.curl.native = new NativeCurl.easy_init if not self.curl.is_ok then return answer_failure(0, "Curl instance is not correctly initialized") var lines = new Array[String] @@ -432,6 +521,8 @@ class CurlMail var err_resp = perform if err_resp != null then return err_resp + self.curl.native.easy_clean + return null end end diff --git a/lib/curl/examples/curl_rest.nit b/lib/curl/examples/curl_rest.nit new file mode 100644 index 0000000..b6d69e3 --- /dev/null +++ b/lib/curl/examples/curl_rest.nit @@ -0,0 +1,43 @@ +# This file is part of NIT ( http://www.nitlanguage.org ). +# +# Copyright 2018 Matthieu Samuel Le Guellaut +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + + +# This example will send a Person object to the specified address +# +import curl +import json + +class Person + serialize + + var name : String + var age : Int + +end + +var url = "http://example.com" + +# POST REQUEST +var my_request = new CurlHTTPRequest(url, method="POST") +var person = new Person("Jean",12) +my_request.body = person.serialize_to_json +my_request.execute + +# # USE WITH SOCKET ADDRESS FAMILY +# var my_unix_request = new CurlHTTPRequest("http:///tmp/", method="POST") +# my_unix_request.body = person.serialize_to_json +# my_unix_request.unix_socket_path = "/tmp/test.sock" +# my_unix_request.execute -- 1.7.9.5