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