1 /*
2 * Copyright (C) 2015-2020 Alibaba Group Holding Limited
3 */
4
5 #include <stdio.h>
6 #include <string.h>
7 #include <stdlib.h>
8
9 #include "httpclient.h"
10 #include "http_wrappers.h"
11 #include "http_form_data.h"
12 #include "http_opts.h"
13
14 /* base64 encode */
httpclient_base64enc(char * out,const char * in)15 static void httpclient_base64enc(char *out, const char *in)
16 {
17 const char code[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=" ;
18 int i = 0, x = 0, l = 0;
19
20 for (; *in; in++) {
21 x = x << 8 | *in;
22 for (l += 8; l >= 6; l -= 6) {
23 out[i++] = code[(x >> (l - 6)) & 0x3f];
24 }
25 }
26 if (l > 0) {
27 x <<= 6 - l;
28 out[i++] = code[x & 0x3f];
29 }
30 for (; i % 4;) {
31 out[i++] = '=';
32 }
33 out[i] = '\0' ;
34 }
35
36 /* parse url according to http[s]://host[:port][/[path]] */
httpclient_parse_url(const char * url,char * scheme,size_t max_scheme_len,char * host,size_t maxhost_len,int * port,char * path,size_t max_path_len)37 static int httpclient_parse_url(const char *url, char *scheme, size_t max_scheme_len, char *host, size_t maxhost_len, int *port, char *path, size_t max_path_len)
38 {
39 char *scheme_ptr = (char *) url;
40 char *host_ptr = NULL;
41 size_t host_len = 0;
42 size_t path_len;
43 char *port_ptr;
44 char *path_ptr;
45 char *fragment_ptr;
46
47 if (url == NULL) {
48 http_err("Could not find url");
49 return HTTP_EPARSE;
50 }
51
52 host_ptr = (char *) strstr(url, "://");
53
54 if (host_ptr == NULL) {
55 http_err("Could not find host");
56 return HTTP_EPARSE; /* URL is invalid */
57 }
58
59 if ( max_scheme_len < host_ptr - scheme_ptr + 1 ) { /* including NULL-terminating char */
60 http_err("Scheme str is too small (%d >= %d)", max_scheme_len, host_ptr - scheme_ptr + 1);
61 return HTTP_EPARSE;
62 }
63 memcpy(scheme, scheme_ptr, host_ptr - scheme_ptr);
64 scheme[host_ptr - scheme_ptr] = '\0';
65
66 host_ptr += 3;
67
68 port_ptr = strchr(host_ptr, ':');
69 if ( port_ptr != NULL ) {
70 uint16_t tport;
71 host_len = port_ptr - host_ptr;
72 port_ptr++;
73 if ( sscanf(port_ptr, "%hu", &tport) != 1) {
74 http_err("Could not find port");
75 return HTTP_EPARSE;
76 }
77 *port = (int)tport;
78 } else {
79 *port = 0;
80 }
81 path_ptr = strchr(host_ptr, '/');
82 if(path_ptr == NULL) {
83 http_err("Could not find '/'");
84 return HTTP_EPARSE;
85 }
86 if ( host_len == 0 ) {
87 host_len = path_ptr - host_ptr;
88 }
89
90 if ( maxhost_len < host_len + 1 ) { /* including NULL-terminating char */
91 http_err("Host str is too small (%d >= %d)", maxhost_len, host_len + 1);
92 return HTTP_EPARSE;
93 }
94 memcpy(host, host_ptr, host_len);
95 host[host_len] = '\0';
96
97 fragment_ptr = strchr(host_ptr, '#');
98 if (fragment_ptr != NULL) {
99 path_len = fragment_ptr - path_ptr;
100 } else {
101 path_len = strlen(path_ptr);
102 }
103
104 if ( max_path_len < path_len + 1 ) { /* including NULL-terminating char */
105 http_err("Path str is too small (%d >= %d)", max_path_len, path_len + 1);
106 return HTTP_EPARSE;
107 }
108 memcpy(path, path_ptr, path_len);
109 path[path_len] = '\0';
110
111 return HTTP_SUCCESS;
112 }
113
httpclient_get_info(httpclient_t * client,char * send_buf,int * send_idx,char * buf,size_t len)114 static int httpclient_get_info(httpclient_t *client, char *send_buf, int *send_idx, char *buf, size_t len) /* 0 on success, err code on failure */
115 {
116 int ret ;
117 int cp_len ;
118 int idx = *send_idx;
119
120 if (len == 0) {
121 len = strlen(buf);
122 }
123
124 do {
125 if ((HTTPCLIENT_SEND_BUF_SIZE - idx) >= len) {
126 cp_len = len ;
127 } else {
128 cp_len = HTTPCLIENT_SEND_BUF_SIZE - idx ;
129 }
130
131 memcpy(send_buf + idx, buf, cp_len) ;
132 idx += cp_len ;
133 len -= cp_len ;
134
135 if (idx == HTTPCLIENT_SEND_BUF_SIZE) {
136 if (client->is_http == false) {
137 http_err("send buffer overflow");
138 return HTTP_EUNKOWN;
139 }
140 ret = http_tcp_send_wrapper(client, send_buf, HTTPCLIENT_SEND_BUF_SIZE) ;
141 if (ret) {
142 return (ret) ;
143 }
144 }
145 } while (len) ;
146
147 *send_idx = idx;
148 return HTTP_SUCCESS;
149 }
150
httpclient_set_custom_header(httpclient_t * client,char * header)151 void httpclient_set_custom_header(httpclient_t *client, char *header)
152 {
153 client->header = header ;
154 }
155
httpclient_basic_auth(httpclient_t * client,char * user,char * password)156 int httpclient_basic_auth(httpclient_t *client, char *user, char *password)
157 {
158 if ((strlen(user) + strlen(password)) >= HTTPCLIENT_AUTHB_SIZE) {
159 return HTTP_EUNKOWN;
160 }
161 client->auth_user = user;
162 client->auth_password = password;
163 return HTTP_SUCCESS;
164 }
165
httpclient_send_auth(httpclient_t * client,char * send_buf,int * send_idx)166 static int httpclient_send_auth(httpclient_t *client, char *send_buf, int *send_idx)
167 {
168 char b_auth[(int)((HTTPCLIENT_AUTHB_SIZE + 3) * 4 / 3 + 3)] ;
169 char base64buff[HTTPCLIENT_AUTHB_SIZE + 3] ;
170
171 httpclient_get_info(client, send_buf, send_idx, "Authorization: Basic ", 0) ;
172 snprintf(base64buff, sizeof(base64buff), "%s:%s", client->auth_user, client->auth_password) ;
173 http_debug("bAuth: %s", base64buff) ;
174 httpclient_base64enc(b_auth, base64buff) ;
175 b_auth[strlen(b_auth) + 2] = '\0' ;
176 b_auth[strlen(b_auth) + 1] = '\n' ;
177 b_auth[strlen(b_auth)] = '\r' ;
178 http_debug("b_auth:%s", b_auth) ;
179 httpclient_get_info(client, send_buf, send_idx, b_auth, 0) ;
180 return HTTP_SUCCESS;
181 }
182
183 static const char *boundary = "----WebKitFormBoundarypNjgoVtFRlzPquKE";
184 /* send request header */
httpclient_send_header(httpclient_t * client,const char * url,int method,httpclient_data_t * client_data)185 static int httpclient_send_header(httpclient_t *client, const char *url, int method, httpclient_data_t *client_data)
186 {
187 char scheme[8] = {0};
188 char *host = NULL;
189 char *path = NULL;
190 int host_size = HTTPCLIENT_MAX_HOST_LEN;
191 int path_size = HTTPCLIENT_MAX_URL_LEN;
192 int len, formdata_len;
193 int total_len = 0;
194 char *send_buf = NULL;
195 char *buf = NULL;
196 int send_buf_size = HTTPCLIENT_SEND_BUF_SIZE;
197 int buf_size = HTTPCLIENT_SEND_BUF_SIZE;
198 char *meth = (method == HTTP_GET) ? "GET" : (method == HTTP_POST) ? "POST" : (method == HTTP_PUT) ? "PUT" : (method == HTTP_DELETE) ? "DELETE" : (method == HTTP_HEAD) ? "HEAD" : "";
199 int ret, port;
200
201 host = (char *) malloc(host_size);
202 if (!host) {
203 http_err("host malloc failed");
204 ret = HTTP_ENOBUFS;
205 goto exit;
206 }
207 memset(host, 0, host_size);
208
209 path = (char *) malloc(path_size);
210 if (!path) {
211 http_err("path malloc failed");
212 ret = HTTP_ENOBUFS;
213 goto exit;
214 }
215 memset(path, 0, path_size);
216
217 send_buf = (char *) malloc(send_buf_size);
218 if (!send_buf) {
219 http_err("send_buf malloc failed");
220 ret = HTTP_ENOBUFS;
221 goto exit;
222 }
223 memset(send_buf, 0, send_buf_size);
224
225 buf = (char *) malloc(buf_size);
226 if (!buf) {
227 http_err("buf malloc failed");
228 ret = HTTP_ENOBUFS;
229 goto exit;
230 }
231 memset(buf, 0, buf_size);
232
233 /* First we need to parse the url (http[s]://host[:port][/[path]]) */
234 int res = httpclient_parse_url(url, scheme, sizeof(scheme), host, host_size, &(port), path, path_size);
235 if (res != HTTP_SUCCESS) {
236 http_err("httpclient_parse_url returned %d", res);
237 ret = res;
238 goto exit;
239 }
240
241 /* Send request */
242 len = 0 ; /* Reset send buffer */
243
244 snprintf(buf, buf_size, "%s %s HTTP/1.1\r\nUser-Agent: AliOS-HTTP-Client/2.1\r\nCache-Control: no-cache\r\nConnection: close\r\nHost: %s\r\n", meth, path, host); /* Write request */
245 ret = httpclient_get_info(client, send_buf, &len, buf, strlen(buf));
246 if (ret) {
247 http_err("Could not write request");
248 ret = HTTP_ECONN;
249 goto exit;
250 }
251
252 /* Send all headers */
253 if (client->auth_user) {
254 httpclient_send_auth(client, send_buf, &len) ; /* send out Basic Auth header */
255 }
256
257 /* Add user header information */
258 if (client->header) {
259 httpclient_get_info(client, send_buf, &len, (char *)client->header, strlen(client->header));
260 }
261
262 if ((formdata_len = httpclient_formdata_len(client_data)) > 0) {
263 total_len += formdata_len;
264
265 memset(buf, 0, buf_size);
266 snprintf(buf, buf_size, "Accept: */*\r\n");
267 httpclient_get_info(client, send_buf, &len, buf, strlen(buf));
268
269 if (client_data->post_content_type != NULL) {
270 memset(buf, 0, buf_size);
271 snprintf(buf, buf_size, "Content-Type: %s\r\n", client_data->post_content_type);
272 httpclient_get_info(client, send_buf, &len, buf, strlen(buf));
273 } else {
274 memset(buf, 0, buf_size);
275 snprintf(buf, buf_size, "Content-Type: multipart/form-data; boundary=%s\r\n", boundary);
276 httpclient_get_info(client, send_buf, &len, buf, strlen(buf));
277 }
278
279 total_len += strlen(boundary) + 8;
280 snprintf(buf, buf_size, "Content-Length: %d\r\n", total_len);
281 httpclient_get_info(client, send_buf, &len, buf, strlen(buf));
282 } else if ( client_data->post_buf != NULL ) {
283 snprintf(buf, buf_size, "Content-Length: %d\r\n", client_data->post_buf_len);
284 httpclient_get_info(client, send_buf, &len, buf, strlen(buf));
285
286 if (client_data->post_content_type != NULL) {
287 snprintf(buf, buf_size, "Content-Type: %s\r\n", client_data->post_content_type);
288 httpclient_get_info(client, send_buf, &len, buf, strlen(buf));
289 }
290 } else {
291 http_debug("Do nothing");
292 }
293
294 /* Close headers */
295 httpclient_get_info(client, send_buf, &len, "\r\n", 0);
296
297 http_debug("Trying to write %d bytes http header:%s", len, send_buf);
298
299 #if CONFIG_HTTP_SECURE
300 if (client->is_http == false) {
301 if (http_ssl_send_wrapper(client, send_buf, len) != len) {
302 http_err("SSL_write failed");
303 ret = HTTP_EUNKOWN;
304 goto exit;
305 }
306
307 ret = HTTP_SUCCESS;
308 goto exit;
309 }
310 #endif
311
312 ret = http_tcp_send_wrapper(client, send_buf, len);
313 if (ret > 0) {
314 http_debug("Written %d bytes, socket = %d", ret, client->socket);
315 } else if ( ret == 0 ) {
316 http_err("ret == 0,Connection was closed by server");
317 ret = HTTP_ECLSD;
318 goto exit; /* Connection was closed by server */
319 } else {
320 http_err("Connection error (send returned %d)", ret);
321 ret = HTTP_ECONN;
322 goto exit;
323 }
324
325 ret = HTTP_SUCCESS;
326
327 exit:
328 if (host) {
329 free(host);
330 host = NULL;
331 }
332
333 if (path) {
334 free(path);
335 path = NULL;
336 }
337
338 if (send_buf) {
339 free(send_buf);
340 send_buf = NULL;
341 }
342
343 if (buf) {
344 free(buf);
345 buf = NULL;
346 }
347
348 return ret;
349 }
350
httpclient_send_userdata(httpclient_t * client,httpclient_data_t * client_data)351 static int httpclient_send_userdata(httpclient_t *client, httpclient_data_t *client_data)
352 {
353 int ret = 0;
354
355 if (client_data->post_buf && client_data->post_buf_len) {
356 http_debug("client_data->post_buf:%s", client_data->post_buf);
357 #if CONFIG_HTTP_SECURE
358 if (client->is_http == false) {
359 if (http_ssl_send_wrapper(client, client_data->post_buf, client_data->post_buf_len) != client_data->post_buf_len) {
360 http_err("SSL_write failed");
361 return HTTP_EUNKOWN;
362 }
363 } else
364 #endif
365 {
366 ret = http_tcp_send_wrapper(client, client_data->post_buf, client_data->post_buf_len);
367 if (ret > 0) {
368 http_debug("Written %d bytes", ret);
369 } else if ( ret == 0 ) {
370 http_debug("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)", ret);
374 return HTTP_ECONN;
375 }
376 }
377 } else if(httpclient_send_formdata(client, client_data) < 0) {
378 return HTTP_ECONN;
379 }
380
381 return HTTP_SUCCESS;
382 }
383
httpclient_recv_data(httpclient_t * client,char * buf,int min_len,int max_len,int * p_read_len)384 static int httpclient_recv_data(httpclient_t *client, char *buf, int min_len, int max_len, int *p_read_len)
385 {
386 int ret = 0;
387 int timeout_ms = 5000;
388
389 if (client->is_http) {
390 ret = http_tcp_recv_wrapper(client, buf, max_len, timeout_ms, p_read_len);
391 }
392 #if CONFIG_HTTP_SECURE
393 else {
394 ret = http_ssl_recv_wrapper(client, buf, max_len, timeout_ms, p_read_len);
395
396 }
397 #endif
398
399 return ret;
400 }
401
httpclient_retrieve_content(httpclient_t * client,char * data,int len,httpclient_data_t * client_data)402 static int httpclient_retrieve_content(httpclient_t *client, char *data, int len, httpclient_data_t *client_data)
403 {
404 int count = 0;
405 int templen = 0;
406 int crlf_pos;
407 client_data->is_more = true;
408
409 if (client_data->response_content_len == -1 && client_data->is_chunked == false) {
410 while(true)
411 {
412 int ret, max_len;
413 if (count + len < client_data->response_buf_len - 1) {
414 memcpy(client_data->response_buf + count, data, len);
415 count += len;
416 client_data->response_buf[count] = '\0';
417 } else {
418 memcpy(client_data->response_buf + count, data, client_data->response_buf_len - 1 - count);
419 client_data->response_buf[client_data->response_buf_len - 1] = '\0';
420 client_data->content_block_len = client_data->response_buf_len - 1;
421 return HTTP_EAGAIN;
422 }
423
424 max_len = MIN(HTTPCLIENT_CHUNK_SIZE - 1, client_data->response_buf_len - 1 - count);
425 if (max_len <= 0) {
426 http_err("%s %d error max_len %d", __func__, __LINE__, max_len);
427 return HTTP_EUNKOWN;
428 }
429 ret = httpclient_recv_data(client, data, 1, max_len, &len);
430
431 /* Receive data */
432 http_debug("data len: %d %d", len, count);
433
434 if (ret == HTTP_ECONN) {
435 http_debug("ret == HTTP_ECONN");
436 client_data->content_block_len = count;
437 return ret;
438 }
439
440 if (len == 0) {/* read no more data */
441 http_debug("no more len == 0");
442 client_data->is_more = false;
443 return HTTP_SUCCESS;
444 }
445 http_debug("in loop %s %d ret %d len %d", __func__, __LINE__, ret, len);
446 }
447 }
448
449 while (true) {
450 size_t readLen = 0;
451
452 if ( client_data->is_chunked && client_data->retrieve_len <= 0) {
453 /* Read chunk header */
454 bool foundCrlf;
455 int n;
456 do {
457 int ret = -1;
458 foundCrlf = false;
459 crlf_pos = 0;
460 data[len] = 0;
461 if (len >= 2) {
462 for (; crlf_pos < len - 2; crlf_pos++) {
463 if ( data[crlf_pos] == '\r' && data[crlf_pos + 1] == '\n' ) {
464 foundCrlf = true;
465 break;
466 }
467 }
468 }
469 if (!foundCrlf) { /* Try to read more */
470 if ( len < HTTPCLIENT_CHUNK_SIZE ) {
471 int new_trf_len;
472 int max_recv = MIN(client_data->response_buf_len, HTTPCLIENT_CHUNK_SIZE);
473 if (max_recv - len - 1 <= 0) {
474 http_err("%s %d error max_len %d", __func__, __LINE__, max_recv - len - 1);
475 return HTTP_EUNKOWN;
476 }
477 ret = httpclient_recv_data(client, data + len, 0, max_recv - len - 1 , &new_trf_len);
478 len += new_trf_len;
479 if ((ret == HTTP_ECONN) || (ret == HTTP_ECLSD && new_trf_len == 0)) {
480 return ret;
481 } else {
482 http_debug("in loop %s %d ret %d len %d", __func__, __LINE__, ret, len);
483 continue;
484 }
485 } else {
486 return HTTP_EUNKOWN;
487 }
488 }
489 http_debug("in loop %s %d len %d ret %d", __func__, __LINE__, len, ret);
490 } while (!foundCrlf);
491 data[crlf_pos] = '\0';
492 n = sscanf(data, "%x", &readLen);/* chunk length */
493 client_data->retrieve_len = readLen;
494 client_data->response_content_len += client_data->retrieve_len;
495 if (n != 1) {
496 http_err("Could not read chunk length");
497 return HTTP_EPROTO;
498 }
499
500 memmove(data, &data[crlf_pos + 2], len - (crlf_pos + 2)); /* Not need to move NULL-terminating char any more */
501 len -= (crlf_pos + 2);
502
503 if ( readLen == 0 ) {
504 /* Last chunk */
505 client_data->is_more = false;
506 http_debug("no more (last chunk)");
507 break;
508 }
509 } else {
510 readLen = client_data->retrieve_len;
511 }
512
513 http_debug("Retrieving %d bytes, len:%d", readLen, len);
514
515 do {
516 int ret;
517 http_debug("readLen %d, len:%d", readLen, len);
518 templen = MIN(len, readLen);
519 if (count + templen < client_data->response_buf_len - 1) {
520 memcpy(client_data->response_buf + count, data, templen);
521 count += templen;
522 client_data->response_buf[count] = '\0';
523 client_data->retrieve_len -= templen;
524 } else {
525 memcpy(client_data->response_buf + count, data, client_data->response_buf_len - 1 - count);
526 client_data->response_buf[client_data->response_buf_len - 1] = '\0';
527 client_data->retrieve_len -= (client_data->response_buf_len - 1 - count);
528 client_data->content_block_len = client_data->response_buf_len - 1;
529 return HTTP_EAGAIN;
530 }
531
532 if ( len >= readLen ) {
533 http_debug("memmove %d %d %d", readLen, len, client_data->retrieve_len);
534 memmove(data, &data[readLen], len - readLen); /* chunk case, read between two chunks */
535 len -= readLen;
536 readLen = 0;
537 client_data->retrieve_len = 0;
538 } else {
539 readLen -= len;
540 }
541
542 if (readLen) {
543 int max_len = MIN(MIN(HTTPCLIENT_CHUNK_SIZE - 1, client_data->response_buf_len - 1 - count), readLen);
544 if (max_len <= 0) {
545 http_err("%s %d error max_len %d", __func__, __LINE__, max_len);
546 return HTTP_EUNKOWN;
547 }
548
549 ret = httpclient_recv_data(client, data, 1, max_len, &len);
550 if (ret == HTTP_ECONN || (ret == HTTP_ECLSD && len == 0)) {
551 return ret;
552 }
553 }
554 } while (readLen);
555
556 if ( client_data->is_chunked ) {
557 if (len < 2) {
558 int new_trf_len = 0, ret;
559 int max_recv = MIN(client_data->response_buf_len - 1 - count + 2, HTTPCLIENT_CHUNK_SIZE - len - 1);
560 if (max_recv <= 0) {
561 http_err("%s %d error max_len %d", __func__, __LINE__, max_recv);
562 return HTTP_EUNKOWN;
563 }
564
565 /* Read missing chars to find end of chunk */
566 ret = httpclient_recv_data(client, data + len, 2 - len, max_recv, &new_trf_len);
567 if ((ret == HTTP_ECONN) || (ret == HTTP_ECLSD && new_trf_len == 0)) {
568 return ret;
569 }
570 len += new_trf_len;
571 }
572 if ( (data[0] != '\r') || (data[1] != '\n') ) {
573 http_err("Format error, %s", data); /* after memmove, the beginning of next chunk */
574 return HTTP_EPROTO;
575 }
576 memmove(data, &data[2], len - 2); /* remove the \r\n */
577 len -= 2;
578 } else {
579 http_err("no more(content-length)");
580 client_data->is_more = false;
581 break;
582 }
583
584 }
585 client_data->content_block_len = count;
586
587 return HTTP_SUCCESS;
588 }
589
httpclient_response_parse(httpclient_t * client,char * data,int len,httpclient_data_t * client_data)590 static int httpclient_response_parse(httpclient_t *client, char *data, int len, httpclient_data_t *client_data)
591 {
592 int crlf_pos;
593 int header_buf_len = client_data->header_buf_len;
594 char *header_buf = client_data->header_buf;
595 int read_result;
596
597 // reset the header buffer
598 if (header_buf) {
599 memset(header_buf, 0, header_buf_len);
600 }
601
602 client_data->response_content_len = -1;
603
604 char *crlf_ptr = strstr(data, "\r\n");
605 if (crlf_ptr == NULL) {
606 http_err("\r\n not found");
607 return HTTP_EPROTO;
608 }
609
610 crlf_pos = crlf_ptr - data;
611 data[crlf_pos] = '\0';
612
613 /* Parse HTTP response */
614 if ( sscanf(data, "HTTP/%*d.%*d %d %*[^\r\n]", &(client->response_code)) != 1 ) {
615 /* Cannot match string, error */
616 http_err("Not a correct HTTP answer : %s", data);
617 return HTTP_EPROTO;
618 }
619
620 if ( (client->response_code < 200) || (client->response_code >= 400) ) {
621 /* Did not return a 2xx code; TODO fetch headers/(&data?) anyway and implement a mean of writing/reading headers */
622 http_debug("Response code %d", client->response_code);
623
624 if (client->response_code == 416) {
625 http_err("Requested Range Not Satisfiable");
626 return HTTP_EUNKOWN;
627 }
628 }
629
630 memmove(data, &data[crlf_pos + 2], len - (crlf_pos + 2) + 1); /* Be sure to move NULL-terminating char as well */
631 len -= (crlf_pos + 2);
632
633 client_data->is_chunked = false;
634
635 /* Now get headers */
636 while ( true ) {
637 char *colon_ptr, *key_ptr, *value_ptr;
638 int key_len, value_len;
639
640 crlf_ptr = strstr(data, "\r\n");
641 if (crlf_ptr == NULL) {
642 if ( len < HTTPCLIENT_CHUNK_SIZE - 1 ) {
643 int new_trf_len = 0;
644 if (HTTPCLIENT_CHUNK_SIZE - len - 1 <= 0) {
645 http_err("%s %d error max_len %d", __func__, __LINE__, HTTPCLIENT_CHUNK_SIZE - len - 1);
646 return HTTP_EUNKOWN;
647 }
648 read_result = httpclient_recv_data(client, data + len, 1, HTTPCLIENT_CHUNK_SIZE - len - 1, &new_trf_len);
649 len += new_trf_len;
650 data[len] = '\0';
651 http_debug("Read %d chars; In buf: [%s]", new_trf_len, data);
652 if ((read_result == HTTP_ECONN) || (read_result == HTTP_ECLSD && new_trf_len == 0)) {
653 return read_result;
654 } else {
655 http_debug("in loop %s %d ret %d len %d", __func__, __LINE__, read_result, len);
656 continue;
657 }
658 } else {
659 http_err("header len > chunksize");
660 return HTTP_EUNKOWN;
661 }
662 }
663
664 crlf_pos = crlf_ptr - data;
665 if (crlf_pos == 0) { /* End of headers */
666 memmove(data, &data[2], len - 2 + 1); /* Be sure to move NULL-terminating char as well */
667 len -= 2;
668 break;
669 }
670
671 colon_ptr = strstr(data, ": ");
672 if (colon_ptr) {
673 if (header_buf_len >= crlf_pos + 2 && header_buf) {
674 /* copy response header to caller buffer */
675 memcpy(header_buf, data, crlf_pos + 2);
676 header_buf += crlf_pos + 2;
677 header_buf_len -= crlf_pos + 2;
678 }
679
680 key_len = colon_ptr - data;
681 value_len = crlf_ptr - colon_ptr - strlen(": ");
682 key_ptr = data;
683 value_ptr = colon_ptr + strlen(": ");
684
685 http_debug("Read header : %.*s: %.*s", key_len, key_ptr, value_len, value_ptr);
686 if (0 == strncasecmp(key_ptr, "Content-Length", key_len)) {
687 sscanf(value_ptr, "%d[^\r]", &(client_data->response_content_len));
688 client_data->retrieve_len = client_data->response_content_len;
689 } else if (0 == strncasecmp(key_ptr, "Transfer-Encoding", key_len)) {
690 if (0 == strncasecmp(value_ptr, "Chunked", value_len)) {
691 client_data->is_chunked = true;
692 client_data->response_content_len = 0;
693 client_data->retrieve_len = 0;
694 }
695 } else if ((client->response_code >= 300 && client->response_code < 400) && (0 == strncasecmp(key_ptr, "Location", key_len))) {
696
697 if ( HTTPCLIENT_MAX_URL_LEN < value_len + 1 ) {
698 http_err("url is too large (%d >= %d)", value_len + 1, HTTPCLIENT_MAX_URL_LEN);
699 return HTTP_EUNKOWN;
700 }
701
702 if(client_data->redirect_url == NULL) {
703 client_data->redirect_url = (char* )malloc(HTTPCLIENT_MAX_URL_LEN);
704 }
705
706 memset(client_data->redirect_url, 0, HTTPCLIENT_MAX_URL_LEN);
707 memcpy(client_data->redirect_url, value_ptr, value_len);
708 client_data->is_redirected = 1;
709 }
710
711 memmove(data, &data[crlf_pos + 2], len - (crlf_pos + 2) + 1); /* Be sure to move NULL-terminating char as well */
712 len -= (crlf_pos + 2);
713 } else {
714 http_err("Could not parse header");
715 return HTTP_EUNKOWN;
716 }
717 }
718
719 return httpclient_retrieve_content(client, data, len, client_data);
720 }
721
722
httpclient_conn(httpclient_t * client,const char * url)723 HTTPC_RESULT httpclient_conn(httpclient_t *client, const char *url)
724 {
725 int ret = HTTP_ECONN;
726 char *host = NULL;
727 char scheme[8] = {0};
728 char *path = NULL;
729 int host_size = HTTPCLIENT_MAX_HOST_LEN;
730 int path_size = HTTPCLIENT_MAX_URL_LEN;
731
732 host = (char *) malloc(host_size);
733 if (!host) {
734 http_err("host malloc failed");
735 ret = HTTP_ENOBUFS;
736 goto exit;
737 }
738 memset(host, 0, host_size);
739
740 path = (char *) malloc(path_size);
741 if (!path) {
742 http_err("path malloc failed");
743 ret = HTTP_ENOBUFS;
744 goto exit;
745 }
746 memset(path, 0, path_size);
747
748 /* First we need to parse the url (http[s]://host[:port][/[path]]) */
749 int res = httpclient_parse_url(url, scheme, sizeof(scheme), host, host_size, &(client->remote_port), path, path_size);
750 if (res != HTTP_SUCCESS) {
751 http_err("httpclient_parse_url returned %d", res);
752 ret = res;
753 goto exit;
754 }
755
756 // http or https
757 if (strcmp(scheme, "https") == 0) {
758 client->is_http = false;
759 }
760 else if (strcmp(scheme, "http") == 0)
761 {
762 client->is_http = true;
763 }
764
765 // default http 80 port, https 443 port
766 if (client->remote_port == 0) {
767 if (client->is_http) {
768 client->remote_port = HTTP_PORT;
769 } else {
770 client->remote_port = HTTPS_PORT;
771 }
772 }
773
774 client->socket = -1;
775 if (client->is_http) {
776 ret = http_tcp_conn_wrapper(client, host);
777 }
778 #if CONFIG_HTTP_SECURE
779 else {
780 ret = http_ssl_conn_wrapper(client, host);
781 }
782 #endif
783
784
785 exit:
786 if (host) {
787 free(host);
788 host = NULL;
789 }
790
791 if (path) {
792 free(path);
793 path = NULL;
794 }
795
796 http_debug("httpclient_conn() result:%d, client:%p", ret, client);
797 return (HTTPC_RESULT)ret;
798 }
799
httpclient_send(httpclient_t * client,const char * url,int method,httpclient_data_t * client_data)800 HTTPC_RESULT httpclient_send(httpclient_t *client, const char *url, int method, httpclient_data_t *client_data)
801 {
802 int ret = HTTP_ECONN;
803
804 if (client->socket < 0) {
805 return (HTTPC_RESULT)ret;
806 }
807
808 ret = httpclient_send_header(client, url, method, client_data);
809 if (ret != 0) {
810 return (HTTPC_RESULT)ret;
811 }
812
813 if (method == HTTP_POST || method == HTTP_PUT) {
814 ret = httpclient_send_userdata(client, client_data);
815 }
816
817 http_debug("httpclient_send() result:%d, client:%p", ret, client);
818 return (HTTPC_RESULT)ret;
819 }
820
821
httpclient_recv(httpclient_t * client,httpclient_data_t * client_data)822 HTTPC_RESULT httpclient_recv(httpclient_t *client, httpclient_data_t *client_data)
823 {
824 int reclen = 0;
825 int ret = HTTP_ECONN;
826 // TODO: header format: name + value must not bigger than HTTPCLIENT_CHUNK_SIZE.
827 char *buf = NULL;
828
829 if (client_data->header_buf_len < HTTPCLIENT_CHUNK_SIZE ||
830 client_data->response_buf_len < HTTPCLIENT_CHUNK_SIZE) {
831 http_err("Error: header buffer or response buffer should not less than %d!", HTTPCLIENT_CHUNK_SIZE);
832 ret = HTTP_EARG;
833 goto exit;
834 }
835
836 buf = (char *) malloc(HTTPCLIENT_CHUNK_SIZE);
837 if (!buf) {
838 http_err("Malloc failed socket fd %d!", client->socket);
839 ret = HTTP_ENOBUFS;
840 goto exit;
841 }
842 memset(buf, 0, HTTPCLIENT_CHUNK_SIZE);
843
844 if (client->socket < 0) {
845 http_err("Invalid socket fd %d!", client->socket);
846 goto exit;
847 }
848
849 if (client_data->is_more) {
850 client_data->response_buf[0] = '\0';
851 ret = httpclient_retrieve_content(client, buf, reclen, client_data);
852 } else {
853 ret = httpclient_recv_data(client, buf, 1, HTTPCLIENT_CHUNK_SIZE - 1, &reclen);
854 if (ret != HTTP_SUCCESS && ret != HTTP_ECLSD) {
855 goto exit;
856 }
857
858 buf[reclen] = '\0';
859
860 if (reclen) {
861 http_debug("reclen:%d, buf:%s", reclen, buf);
862 ret = httpclient_response_parse(client, buf, reclen, client_data);
863 }
864 }
865
866 http_debug("httpclient_recv_data() result:%d, client:%p", ret, client);
867
868 exit:
869 if (buf) {
870 free(buf);
871 buf = NULL;
872 }
873
874 return (HTTPC_RESULT)ret;
875 }
876
httpclient_clse(httpclient_t * client)877 void httpclient_clse(httpclient_t *client)
878 {
879 if (client->is_http) {
880 http_tcp_close_wrapper(client);
881 }
882 #if CONFIG_HTTP_SECURE
883 else
884 http_ssl_close_wrapper(client);
885 #endif
886
887 client->socket = -1;
888 http_debug("httpclient_clse() client:%p", client);
889 }
890
httpclient_get_response_code(httpclient_t * client)891 int httpclient_get_response_code(httpclient_t *client)
892 {
893 return client->response_code;
894 }
895
httpclient_get_response_header_value(char * header_buf,char * name,int * val_pos,int * val_len)896 int httpclient_get_response_header_value(char *header_buf, char *name, int *val_pos, int *val_len)
897 {
898 char *data = header_buf;
899 char *crlf_ptr, *colon_ptr, *key_ptr, *value_ptr;
900 int key_len, value_len;
901
902 if (header_buf == NULL || name == NULL || val_pos == NULL || val_len == NULL )
903 return -1;
904
905 while (true) {
906 crlf_ptr = strstr(data, "\r\n");
907 colon_ptr = strstr(data, ": ");
908 if (crlf_ptr && colon_ptr) {
909 key_len = colon_ptr - data;
910 value_len = crlf_ptr - colon_ptr - strlen(": ");
911 key_ptr = data;
912 value_ptr = colon_ptr + strlen(": ");
913
914 http_debug("Response header: %.*s: %.*s", key_len, key_ptr, value_len, value_ptr);
915 if (0 == strncasecmp(key_ptr, name, key_len)) {
916 *val_pos = value_ptr - header_buf;
917 *val_len = value_len;
918 return 0;
919 } else {
920 data = crlf_ptr + 2;
921 continue;
922 }
923 } else
924 return -1;
925
926 }
927 }
928
httpclient_prepare(httpclient_data_t * client_data,int header_size,int resp_size)929 HTTPC_RESULT httpclient_prepare(httpclient_data_t *client_data, int header_size, int resp_size)
930 {
931 HTTPC_RESULT ret = HTTP_SUCCESS;
932
933 if (!client_data)
934 return HTTP_EUNKOWN;
935
936 if (header_size < HTTPCLIENT_CHUNK_SIZE || resp_size < HTTPCLIENT_CHUNK_SIZE) {
937 http_err("Error: header buffer or response buffer should not less than %d!", HTTPCLIENT_CHUNK_SIZE);
938 return HTTP_EARG;
939 }
940
941 memset(client_data, 0, sizeof(httpclient_data_t));
942
943 client_data->header_buf = (char *) malloc (header_size);
944 client_data->response_buf = (char *) malloc (resp_size);
945
946 if (client_data->header_buf == NULL || client_data->response_buf == NULL){
947 http_err("httpc_prepare alloc memory failed");
948 if(client_data->header_buf){
949 free(client_data->header_buf);
950 client_data->header_buf = NULL;
951 }
952
953 if(client_data->response_buf){
954 free(client_data->response_buf);
955 client_data->response_buf = NULL;
956 }
957 ret = HTTP_EUNKOWN;
958 goto finish;
959 }
960
961 http_debug("httpc_prepare alloc memory");
962
963 client_data->header_buf_len = header_size;
964 client_data->response_buf_len = resp_size;
965 client_data->post_buf_len = 0;
966
967 client_data->is_redirected = 0;
968 client_data->redirect_url = NULL;
969
970 finish:
971 return ret;
972 }
973
httpclient_reset(httpclient_data_t * client_data)974 void httpclient_reset(httpclient_data_t *client_data)
975 {
976 char *response_buf = client_data->response_buf;
977 char *header_buf = client_data->header_buf;
978 int response_buf_len = client_data->response_buf_len;
979 int header_buf_len = client_data->header_buf_len;
980
981 memset(client_data, 0, sizeof(httpclient_data_t));
982
983 client_data->response_buf = response_buf;
984 client_data->header_buf = header_buf;
985 client_data->response_buf_len = response_buf_len;
986 client_data->header_buf_len = header_buf_len;
987 }
988
httpclient_unprepare(httpclient_data_t * client_data)989 HTTPC_RESULT httpclient_unprepare(httpclient_data_t *client_data)
990 {
991 HTTPC_RESULT ret = HTTP_SUCCESS;
992
993 if (!client_data){
994 ret = HTTP_EUNKOWN;
995 goto finish;
996 }
997
998 if(client_data->header_buf){
999 free(client_data->header_buf);
1000 client_data->header_buf = NULL;
1001 }
1002
1003 if(client_data->response_buf){
1004 free(client_data->response_buf);
1005 client_data->response_buf = NULL;
1006 }
1007
1008 client_data->header_buf_len = 0;
1009 client_data->response_buf_len = 0;
1010
1011 client_data->is_redirected = 0;
1012 if (client_data->redirect_url) {
1013 free(client_data->redirect_url);
1014 client_data->redirect_url = NULL;
1015 }
1016
1017 finish:
1018 return ret;
1019 }
1020