1 /*
2 * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
3 * Copyright (C) 2017 - ESI-Group - Cedric DELAMARRE
4 *
5 *
6 * This file is hereby licensed under the terms of the GNU GPL v2.0,
7 * pursuant to article 5.3.4 of the CeCILL v.2.1.
8 * This file was originally licensed under the terms of the CeCILL v2.1,
9 * and continues to be available under such terms.
10 * For more information, see the COPYING file which you should have received
11 * along with this program.
12 *
13 */
14 /*--------------------------------------------------------------------------*/
15 
16 #include <curl/curl.h>
17 #include "webtools_gw.hxx"
18 #include "function.hxx"
19 #include "string.hxx"
20 #include "double.hxx"
21 #include "json.hxx"
22 #include "sciCurl.hxx"
23 
24 extern "C"
25 {
26 #include "localization.h"
27 #include "Scierror.h"
28 #include "sciprint.h"
29 #include "sci_malloc.h"
30 }
31 
32 /*--------------------------------------------------------------------------*/
sci_http_put_post(types::typed_list & in,types::optional_list & opt,int _iRetCount,types::typed_list & out,const char * fname)33 types::Function::ReturnValue sci_http_put_post(types::typed_list &in, types::optional_list &opt, int _iRetCount, types::typed_list &out, const char* fname)
34 {
35     SciCurl* sciCurlObj = SciCurl::getInstance();
36     CURLcode res = CURLE_OK;
37     struct curl_slist *headers = NULL;
38     bool isJson = false;
39     char* pcData = NULL;
40 
41     if (in.size() < 1 || in.size() > 2)
42     {
43         Scierror(77, _("%s: Wrong number of input argument(s): %d to %d expected.\n"), fname, 1, 2);
44         return types::Function::Error;
45     }
46 
47     if (_iRetCount > 2)
48     {
49         Scierror(78, _("%s: Wrong number of output argument(s): %d to %d expected.\n"), fname, 1, 2);
50         return types::Function::Error;
51     }
52 
53     // get URL
54     if(in[0]->isString() == false && in[0]->getAs<types::String>()->isScalar() == false)
55     {
56         Scierror(999, _("%s: Wrong type for input argument #%d: A scalar string expected.\n"), fname, 1);
57         return types::Function::Error;
58     }
59 
60     CURL* curl = curl_easy_init();
61     if(curl == nullptr)
62     {
63         Scierror(999, _("%s: CURL initialization failed.\n"), fname);
64         return types::Function::Error;
65     }
66 
67     sciCurlObj->setCommonHeaders(curl);
68 
69     char* pcURL = wide_string_to_UTF8(in[0]->getAs<types::String>()->get(0));
70     curl_easy_setopt(curl, CURLOPT_URL, pcURL);
71     FREE(pcURL);
72 
73     sciCurlObj->getResultAsObject(curl);
74     if(strcmp(fname, "http_put") == 0)
75     {
76         curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, "PUT");
77     }
78     else if(strcmp(fname, "http_patch") == 0)
79     {
80         curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, "PATCH");
81     }
82     else
83     {
84         curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, "POST");
85     }
86 
87     // common optional argument
88     if(checkCommonOpt((void*)curl, opt, fname))
89     {
90         return types::Function::Error;
91     }
92 
93     // set proxy information
94     if(sciCurlObj->setProxy(curl))
95     {
96         Scierror(999, _("%s: Wrong proxy information, please check in the 'internet' Scilab preference.\n"), fname);
97         return types::Function::Error;
98     }
99 
100     // specific optional argument
101     for (const auto& o : opt)
102     {
103         if(o.first == L"format")
104         {
105             if(o.second->isString() == false && o.second->getAs<types::String>()->isScalar() == false)
106             {
107                 Scierror(999, _("%s: Wrong type for input argument #%s: A scalar string expected.\n"), fname, o.first.data());
108                 return types::Function::Error;
109             }
110 
111             if( (wcscmp(o.second->getAs<types::String>()->get(0), L"JSON") == 0) ||
112                 (wcscmp(o.second->getAs<types::String>()->get(0), L"json") == 0))
113             {
114                 isJson = true;
115             }
116         }
117     }
118 
119     if(in.size() > 1)
120     {
121         // get data
122         if(in[1]->isString() && in[1]->getAs<types::String>()->isScalar())
123         {
124             pcData = wide_string_to_UTF8(in[1]->getAs<types::String>()->get(0));
125         }
126         else
127         {
128             pcData = os_strdup(toJSON(in[1]).c_str());
129             isJson = true;
130         }
131 
132         if(isJson)
133         {
134             headers = curl_slist_append(headers, "Accept: application/json");
135             headers = curl_slist_append(headers, "Content-Type: application/json");
136             headers = curl_slist_append(headers, "charsets: utf-8");
137             curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);
138         }
139 
140         curl_easy_setopt(curl, CURLOPT_POSTFIELDS, pcData);
141     }
142 
143     res = curl_easy_perform(curl);
144     if (pcData)
145     {
146         FREE(pcData);
147     }
148 
149     if(headers)
150     {
151         curl_slist_free_all(headers);
152     }
153 
154     if(res != CURLE_OK)
155     {
156         Scierror(999, _("%s: CURL execution failed.\n%s\n"), fname, curl_easy_strerror(res));
157         sciCurlObj->clear();
158         return types::Function::Error;
159     }
160 
161     out.push_back(sciCurlObj->getResult());
162 
163     if(_iRetCount == 2)
164     {
165         long http_code = 0;
166         curl_easy_getinfo (curl, CURLINFO_RESPONSE_CODE, &http_code);
167         out.push_back(new types::Double((double)http_code));
168     }
169 
170     curl_easy_cleanup(curl);
171     return types::Function::OK;
172 }
173