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