1 /*
2  * Copyright (C) 2015-2020 Alibaba Group Holding Limited
3  */
4 
5 #include <stdio.h>
6 #include <stdlib.h>
7 #include <string.h>
8 #include <errno.h>
9 
10 #include "httpclient.h"
11 #include "http_form_data.h"
12 #include "http_wrappers.h"
13 
14 static formdata_info_t formdata_info[CLIENT_FORM_DATA_NUM] = {0};
15 
form_data_clear(formdata_node_t * form_data)16 static void form_data_clear(formdata_node_t* form_data) {
17     if(form_data != NULL) {
18         form_data_clear(form_data->next);
19         form_data->next = NULL;
20         if(form_data->data != NULL) {
21             free(form_data->data);
22         }
23         free(form_data);
24     }
25 }
26 
found_formdata_info(httpclient_data_t * client_data)27 formdata_info_t* found_formdata_info(httpclient_data_t * client_data) {
28     int i;
29 
30     for(i = 0; i < CLIENT_FORM_DATA_NUM; i++) {
31         if((formdata_info[i].client_data == client_data)
32            && (formdata_info[i].is_used == 1)) {
33             break;
34         }
35     }
36 
37     if(i == CLIENT_FORM_DATA_NUM) {
38         return NULL;
39     }
40 
41     return &formdata_info[i];
42 }
43 
found_empty_formdata_info()44 static formdata_info_t* found_empty_formdata_info() {
45     int i;
46 
47     for(i = 0; i < CLIENT_FORM_DATA_NUM; i++) {
48         if(formdata_info[i].is_used == 0) {
49             break;
50         }
51     }
52 
53     if(i == CLIENT_FORM_DATA_NUM) {
54         return NULL;
55     }
56 
57     return &formdata_info[i];
58 }
59 
60 #define TEXT_FORMAT              "\r\nContent-Disposition: %s; name=\"%s\"\r\n\r\n%s\r\n"
61 #define TEXT_CONTENT_TYPE_FORMAT "\r\nContent-Disposition :%s; name=\"%s\"\r\nContent-Type:%s\r\n\r\n%s\r\n"
httpclient_formdata_addtext(httpclient_data_t * client_data,char * content_disposition,char * content_type,char * name,char * data,int data_len)62 int httpclient_formdata_addtext(httpclient_data_t* client_data, char* content_disposition, char* content_type, char* name, char* data, int data_len)
63 {
64     int buf_len;
65     formdata_info_t* data_info;
66     formdata_node_t* previous;
67     formdata_node_t* current;
68 
69     if((content_disposition == NULL) || (name == NULL) || (data == NULL) || (data_len == 0)) {
70         http_err("%s:%d invalid params", __func__, __LINE__);
71         return -1;
72     }
73 
74     if(strlen(data) > data_len) {
75         http_err("%s:%d invalid data_len %d strlen data %d", __func__, __LINE__, data_len, strlen(data));
76         return -1;
77     }
78 
79     if((data_info = found_formdata_info(client_data)) == NULL) {
80         if((data_info = found_empty_formdata_info()) == NULL) {
81             http_err("%s:%d found no client_data info", __func__, __LINE__);
82             return -1;
83         }
84     }
85 
86     if(data_info->is_used == 0) {
87         data_info->is_used = 1;
88         data_info->client_data = client_data;
89         data_info->form_data = (formdata_node_t *)malloc(sizeof(formdata_node_t));
90         if(data_info->form_data == NULL) {
91             data_info->is_used = 0;
92             http_err("%s:%d form data malloc failed", __func__, __LINE__);
93             return -1;
94         }
95         previous = data_info->form_data;
96         current = data_info->form_data;
97     }
98     else {
99         current = data_info->form_data;
100 
101         while(current->next != NULL) {
102             current = current->next;
103         }
104 
105         current->next = (formdata_node_t *)malloc(sizeof(formdata_node_t));
106         if(current->next == NULL) {
107             http_err("%s:%d form data malloc failed", __func__, __LINE__);
108             return -1;
109         }
110         previous = current;
111         current = current->next;
112     }
113 
114     memset(current, 0, sizeof(formdata_node_t));
115     if(content_type == NULL) {
116         buf_len = strlen(TEXT_FORMAT) - 6 + strlen(content_disposition) + strlen(name) + strlen(data) + 1;
117     }
118     else {
119         buf_len = strlen(TEXT_CONTENT_TYPE_FORMAT) - 8 + strlen(content_disposition) + strlen(name) + strlen(data) + strlen(content_type) + 1;
120     }
121     current->data = (char*)malloc(buf_len+1);
122     if( current->data == NULL) {
123         if(previous == current ) {
124             free(current);
125             memset(data_info, 0, sizeof(formdata_info_t));
126         }
127         else {
128             free(current);
129             previous->next = NULL;
130         }
131         http_err("%s:%d data malloc failed", __func__, __LINE__);
132         return -1;
133     }
134     memset(current->data, 0, sizeof(buf_len));
135     if(content_type == NULL) {
136         snprintf(current->data, buf_len, TEXT_FORMAT, content_disposition, name, data);
137         current->data_len = strlen(current->data);
138     }
139     else {
140         snprintf(current->data, buf_len, TEXT_CONTENT_TYPE_FORMAT, content_disposition, name, content_type, data);
141         current->data_len = strlen(current->data);
142     }
143     return 0;
144 }
145 
get_url_file_name(char * url)146 static int get_url_file_name(char* url)
147 {
148     char * ptr = url;
149     int offset = 0;
150     int i = 0;
151 
152     while(*ptr != '\0')
153     {
154         i++;
155         if(*ptr == '/') {
156             offset = i;
157         }
158         ptr++;
159     }
160     return offset;
161 }
162 
httpclient_clear_form_data(httpclient_data_t * client_data)163 void httpclient_clear_form_data(httpclient_data_t * client_data)
164 {
165     formdata_info_t * data_info;
166     formdata_node_t * current;
167 
168     data_info = found_formdata_info(client_data);
169 
170     if(data_info == NULL) {
171         http_err("No form data info found");
172         return;
173     }
174 
175     current = data_info->form_data;
176     if(current != NULL) {
177         form_data_clear(current);
178     }
179     else {
180         http_err("No form data in form data info");
181     }
182 
183     memset(data_info, 0, sizeof(formdata_info_t));
184 }
185 
186 #define FILE_FORMAT_START                "\r\nContent-Disposition: %s; name=\"%s\"; filename=\"%s\"\r\n"
187 #define FILE_FORMAT_END                  "\r\nContent-Disposition: %s; name=\"%s\"; filename=\"\"\r\n"
188 #define FILE_FORMAT_CONTENT_TYPE_START   "\r\nContent-Disposition: %s; name=\"%s\"; filename=\"%s\"\r\nContent-Type: %s\r\n\r\n"
httpclient_formdata_addfile(httpclient_data_t * client_data,char * content_disposition,char * name,char * content_type,char * file_path)189 int httpclient_formdata_addfile(httpclient_data_t* client_data, char* content_disposition, char* name, char* content_type, char* file_path)
190 {
191     int buf_len;
192     formdata_info_t* data_info;
193     formdata_node_t* previous;
194     formdata_node_t* current;
195 
196     if((content_disposition == NULL) || (name == NULL) || (file_path == NULL)) {
197         http_err("%s:%d invalid params", __func__, __LINE__);
198         return -1;
199     }
200 
201     if((data_info = found_formdata_info(client_data)) == NULL) {
202         if((data_info = found_empty_formdata_info()) == NULL) {
203             http_err("%s:%d found no client_data info", __func__, __LINE__);
204             return -1;
205         }
206     }
207 
208     if(data_info->is_used == 0) {
209         data_info->is_used = 1;
210         data_info->client_data = client_data;
211         data_info->form_data = (formdata_node_t *)malloc(sizeof(formdata_node_t));
212         if(data_info->form_data == NULL) {
213             data_info->is_used = 0;
214             http_err("%s:%d data malloc failed", __func__, __LINE__);
215             return -1;
216         }
217 
218         previous = data_info->form_data;
219         current = data_info->form_data;
220     }
221     else {
222         current = data_info->form_data;
223 
224         while(current->next != NULL) {
225             current = current->next;
226         }
227 
228         current->next = (formdata_node_t *)malloc(sizeof(formdata_node_t));
229         if(current->next == NULL) {
230             http_err("%s:%d data malloc failed", __func__, __LINE__);
231             return -1;
232         }
233         previous = current;
234         current = current->next;
235     }
236 
237     memset(current, 0, sizeof(formdata_node_t));
238     if(content_type == NULL) {
239         buf_len = strlen(FILE_FORMAT_START) - 6 + strlen(content_disposition) + strlen(name) + strlen(file_path) - get_url_file_name(file_path) + 1;
240     }
241     else {
242         buf_len = strlen(FILE_FORMAT_CONTENT_TYPE_START) - 8 + strlen(content_disposition) + strlen(name) + strlen(file_path) - get_url_file_name(file_path) + strlen(content_type) + 1;
243     }
244     current->data = (char*)malloc(buf_len + 1);
245     if( current->data == NULL) {
246         if(previous == current ) {
247             free(current);
248         } else {
249             free(current);
250             previous->next = NULL;
251         }
252         http_err("%s:%d data malloc failed", __func__, __LINE__);
253         return -1;
254     }
255     memset(current->data, 0, sizeof(buf_len));
256 
257     current->is_file = 1;
258 
259     memcpy(current->file_path, file_path, strlen(file_path));
260     if(content_type == NULL) {
261         snprintf(current->data, buf_len, FILE_FORMAT_START, content_disposition, name, file_path + get_url_file_name(file_path));
262     }
263     else {
264         snprintf(current->data, buf_len, FILE_FORMAT_CONTENT_TYPE_START, content_disposition, name, file_path + get_url_file_name(file_path), content_type);
265     }
266     current->data_len = strlen(current->data);
267     return 0;
268 }
269 
270 static const char *boundary = "----WebKitFormBoundarypNjgoVtFRlzPquKE";
httpclient_formdata_len(httpclient_data_t * client_data)271 int httpclient_formdata_len(httpclient_data_t *client_data)
272 {
273 	int total_len = 0;
274 	formdata_info_t* data_info = NULL;
275 	formdata_node_t * current;
276 
277     data_info = found_formdata_info(client_data);
278     if ((NULL == data_info) || (0 == data_info->is_used)) {
279     	return 0;
280     }
281 
282     current = data_info->form_data;
283     /* calculate content-length*/
284     do {
285 #if CONFIG_HTTP_FILE_OPERATE
286         if(current->is_file == 1) {
287             FILE* fd;
288             long size;
289 
290             fd = fopen(current->file_path, "rb");
291             if(fd == NULL) {
292                 http_err("%s: open file(%s) failed errno=%d", __func__, current->file_path, errno);
293                 return -1;
294             }
295 
296             fseek(fd,0,SEEK_END);
297             size=ftell(fd);
298             fseek(fd,0,SEEK_SET);
299             fclose(fd);
300             total_len += size;
301         }
302 #endif
303 
304         total_len += current->data_len;
305         total_len += strlen(boundary) + 4;
306         current = current->next;
307     } while(current != NULL);
308 
309 
310     return total_len;
311 }
312 
httpclient_send_formdata(httpclient_t * client,httpclient_data_t * client_data)313 int httpclient_send_formdata(httpclient_t *client, httpclient_data_t *client_data)
314 {
315 	int ret;
316     formdata_info_t* data_info = NULL;
317 	formdata_node_t * current;
318 	char data[HTTP_DATA_SIZE] = {0};
319 
320     data_info = found_formdata_info(client_data);
321     if ((NULL == data_info) || (0 == data_info->is_used)) {
322     	return 0;
323     }
324 
325     current = data_info->form_data;
326 
327     while(current != NULL) {
328         /* set boundary */
329         memset(data, 0, sizeof(data));
330         snprintf(data, sizeof(data), "\r\n--%s", boundary);
331         ret = http_tcp_send_wrapper(client, data, strlen(data));
332         if (ret <= 0) {
333             return -1;
334         }
335 
336         ret = http_tcp_send_wrapper(client, current->data, current->data_len);
337         if (ret <= 0) {
338             return -1;
339         }
340 
341         if(current->is_file == 1 ) {
342             break;
343         }
344         current = current->next;
345     }
346 
347     if(current == NULL) {
348         return -1;
349     }
350 
351 #if CONFIG_HTTP_FILE_OPERATE
352     {
353 	    FILE* fd = fopen(current->file_path, "rb");
354 	    if(fd == NULL) {
355 	        http_err("%s: open file(%s) failed errno=%d", __func__, current->file_path, errno);
356 	        return -1;
357 	    }
358 
359 	    while(!feof(fd)) {
360 	        ret = fread(data, 1, sizeof(data), fd);
361 	        if(ret <= 0) {
362 	            http_err("fread failed returned %d errno=%d", ret, errno);
363 	            return -1;
364 	        }
365 
366 	        ret = http_tcp_send_wrapper(client, data, ret);
367 	        if (ret > 0) {
368 	            http_err("Written %d bytes", ret);
369 	        } else if ( ret == 0 ) {
370 	            http_err("ret == 0,Connection was closed by server");
371 	            return HTTP_ECLSD; /* Connection was closed by server */
372 	        } else {
373 	            http_err("Connection error (send returned %d) errno=%d", ret, errno);
374 	            return HTTP_ECONN;
375 	        }
376 
377 	        memset(data, 0, sizeof(data));
378 	        aos_msleep(100);
379 	    }
380 
381 	    fclose(fd);
382     }
383 #endif
384 
385     current = current->next;
386     while(current != NULL) {
387         memset(data, 0, sizeof(data));
388         snprintf(data, sizeof(data), "\r\n--%s", boundary);
389         ret = http_tcp_send_wrapper(client, data, strlen(data));
390         if (ret <= 0) {
391             return -1;
392         }
393 
394         ret = http_tcp_send_wrapper(client, current->data, current->data_len);
395         if (ret <= 0) {
396             return -1;
397         }
398         current = current->next;
399     }
400 
401     memset(data, 0, sizeof(data));
402     snprintf(data, sizeof(data), "\r\n--%s--\r\n", boundary);
403     ret = http_tcp_send_wrapper(client, data, strlen(data));
404     if (ret <= 0) {
405         return -1;
406     }
407 
408     return 0;
409 }
410