[webtools] Header fixed about User-Agent
[scilab.git] / scilab / modules / webtools / sci_gateway / cpp / sci_http_upload.cpp
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 "struct.hxx"
22 #include "sciCurl.hxx"
23 #include "json.hxx"
24
25 extern "C"
26 {
27 #include "localization.h"
28 #include "Scierror.h"
29 #include "sciprint.h"
30 #include "sci_malloc.h"
31 #include "getFullFilename.h"
32 }
33
34 /*--------------------------------------------------------------------------*/
35 static const char fname[] = "http_upload";
36 types::Function::ReturnValue sci_http_upload(types::typed_list &in, types::optional_list &opt, int _iRetCount, types::typed_list &out)
37 {
38     SciCurl* sciCurlObj = SciCurl::getInstance();
39     CURLcode res = CURLE_OK;
40
41     if (in.size() < 3 || in.size() > 4)
42     {
43         Scierror(77, _("%s: Wrong number of input argument(s): %d to %d expected.\n"), fname, 3, 4);
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     // get input file name
74     if(in[1]->isString() == false)
75     {
76         Scierror(999, _("%s: Wrong type for input argument #%d: A matrix string expected.\n"), fname, 2);
77         return types::Function::Error;
78     }
79
80     types::String* pStrFiles = in[1]->getAs<types::String>();
81     std::vector<char*> files;
82     for(int i = 0; i < pStrFiles->getSize(); i++)
83     {
84         wchar_t* pwcFileName = getFullFilenameW(pStrFiles->get(i));
85         files.push_back(wide_string_to_UTF8(pwcFileName));
86         FREE(pwcFileName);
87     }
88
89     // get variable name server side
90     if(in[2]->isString() == false && in[2]->getAs<types::String>()->isScalar() == false)
91     {
92         Scierror(999, _("%s: Wrong type for input argument #%d: A scalar string expected.\n"), fname, 3);
93         return types::Function::Error;
94     }
95
96     char* pcVarName = wide_string_to_UTF8(in[2]->getAs<types::String>()->get(0));
97
98     struct curl_httppost *formpost = NULL;
99     struct curl_httppost *lastptr  = NULL;
100
101     // /!\ This doesn't work with nodejs multer array /!\
102     // struct curl_forms form[files.size()+1];
103     // int iter = 0;
104     // for(auto f : files)
105     // {
106     //     form[iter].option  = CURLFORM_FILE;
107     //     form[iter++].value = f;
108     // }
109     //
110     // form[iter].option = CURLFORM_END;
111     //
112     // curl_formadd(&formpost,
113     //              &lastptr,
114     //              CURLFORM_COPYNAME, pcVarName,
115     //              CURLFORM_ARRAY, form,
116     //              CURLFORM_END);
117
118     for(auto f : files)
119     {
120         curl_formadd(&formpost,
121                      &lastptr,
122                      CURLFORM_COPYNAME, pcVarName,
123                      CURLFORM_FILE, f,
124                      CURLFORM_END);
125     }
126
127     FREE(pcVarName);
128
129     if(in.size() > 3)
130     {
131         // get data
132         if(in[3]->isStruct() == false && in[3]->getAs<types::Struct>()->isScalar() == false)
133         {
134             Scierror(999, _("%s: Wrong type for input argument #%d: A structure of size %d expected.\n"), fname, 3, 1);
135             return types::Function::Error;
136         }
137
138         types::Struct* pStruct = in[3]->getAs<types::Struct>();
139         std::unordered_map<std::wstring, int> fieldsMap = pStruct->get(0)->getFields();
140         std::vector<types::InternalType*> pITData = pStruct->get(0)->getData();
141         for (const auto & field : fieldsMap)
142         {
143             char* pcFieldName = wide_string_to_UTF8(field.first.data());
144             std::string strData(toJSON(pITData[field.second]));
145             //remove " @start and @end of string
146             if (strData.front() == '\"' && strData.back() == '\"')
147             {
148                 strData = strData.substr(1);
149                 strData.pop_back();
150             }
151             sciprint("|%s|: |%s|\n", pcFieldName, strData.data());
152             curl_formadd(&formpost,
153                          &lastptr,
154                          CURLFORM_COPYNAME, pcFieldName,
155                          CURLFORM_COPYCONTENTS, strData.data(),
156                          CURLFORM_END);
157
158             FREE(pcFieldName);
159         }
160     }
161
162     curl_easy_setopt(curl, CURLOPT_HTTPPOST, formpost);
163
164     // set proxy information
165     if(sciCurlObj->setProxy(curl))
166     {
167         Scierror(999, _("%s: Wrong proxy information, please check in the 'internet' Scilab preference.\n"), fname);
168         return types::Function::Error;
169     }
170
171     // common optional argument
172     if(checkCommonOpt((void*)curl, opt, fname))
173     {
174         return types::Function::Error;
175     }
176
177     // specific optional argument
178     for (const auto& o : opt)
179     {
180         if (o.first == L"method")
181         {
182             if(o.second->isString() == false && o.second->getAs<types::String>()->isScalar() == false)
183             {
184                 Scierror(999, _("%s: Wrong type for input argument #%s: A scalar string expected.\n"), fname, o.first.data());
185                 return types::Function::Error;
186             }
187
188             wchar_t* pMeth = o.second->getAs<types::String>()->get(0);
189             if(wcscmp(pMeth, L"PUT") == 0)
190             {
191                 curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, "PUT");
192             }
193             else if(wcscmp(pMeth, L"POST") != 0)
194             {
195                 Scierror(999, _("%s: Wrong value for input argument #%s: 'PUT' or 'POST' expected.\n"), fname, o.first.data());
196                 return types::Function::Error;
197             }
198         }
199     }
200
201     sciCurlObj->getResultAsObject(curl);
202     res = curl_easy_perform(curl);
203     for(auto f : files)
204     {
205         FREE(f);
206     }
207
208     curl_formfree(formpost);
209
210     if(res != CURLE_OK)
211     {
212         Scierror(999, _("%s: CURL execution failed.\n%s\n"), fname, curl_easy_strerror(res));
213         sciCurlObj->clear();
214         return types::Function::Error;
215     }
216
217     out.push_back(sciCurlObj->getResult());
218
219     if(_iRetCount == 2)
220     {
221         long http_code = 0;
222         curl_easy_getinfo (curl, CURLINFO_RESPONSE_CODE, &http_code);
223         out.push_back(new types::Double((double)http_code));
224     }
225
226     curl_easy_cleanup(curl);
227     return types::Function::OK;
228 }