blob: f83ae359f7a51fec73512fbcae9e21237a6e8af1 [file] [log] [blame]
liubin281ac462023-07-19 14:22:54 +08001/*************************************************************
2Description:
3 MBTK HTTP c file.
4Author:
5 LiuBin
6Date:
7 2020/4/30 13:51:42
8*************************************************************/
9#include <stdio.h>
10#include <stdlib.h>
11#include <ctype.h>
12#include <string.h>
LUOJian99f31df2023-09-28 17:03:24 +080013#include <fcntl.h>
14#include <unistd.h>
15#include <sys/stat.h>
liubin281ac462023-07-19 14:22:54 +080016
17#include "mbtk_http_base.h"
18#include "mbtk_http.h"
19#include "mbtk_http_chunks.h"
20
21/*************************************************************
22 Constants and Macros
23*************************************************************/
24
25/*************************************************************
26 Variables:local
27*************************************************************/
28static mbtk_http_handle_t http_handles[HTTP_HANDLE_MAX] =
29{
30 {
31 .id = -1,
32 .data_cb = NULL,
33 .session_cnt = 0,
34 .session = {NULL}
35 }
36};
37
38/*************************************************************
39 Variables:public
40*************************************************************/
41
42
43/*************************************************************
44 Local Function Declaration
45*************************************************************/
46
47
48/*************************************************************
49 Local Function Definitions
50*************************************************************/
51static void http_session_free(mbtk_http_session_t *session)
52{
53 if(session)
54 {
55 if(session->req.header_cnt > 0)
56 {
57 int index;
58 for(index = 0; index < HTTP_REQUEST_HEADER_MAX; index++)
59 {
60 if(session->req.req_h[index] != NULL)
61 {
62 if(session->req.req_h[index]->value)
63 free(session->req.req_h[index]->value);
64 free(session->req.req_h[index]);
65 session->req.req_h[index] = NULL;
66 }
67 }
68 session->req.header_cnt = 0;
69 }
70
71 if(session->req.content)
72 {
73 free(session->req.content);
74 session->req.content = NULL;
75 }
76
77 if(session->rsp.header_cnt > 0)
78 {
79 int index;
80 for(index = 0; index < HTTP_REQUEST_HEADER_MAX; index++)
81 {
82 if(session->rsp.rsp_h[index] != NULL)
83 {
84 if(session->rsp.rsp_h[index]->value)
85 free(session->rsp.rsp_h[index]->value);
86 free(session->rsp.rsp_h[index]);
87 session->rsp.rsp_h[index] = NULL;
88 }
89 }
90 session->rsp.header_cnt = 0;
91 }
92
93 free(session);
94 }
95}
96
97static int http_session_close(mbtk_http_session_t *session)
98{
99 if(session)
100 {
101 if(session->sock_fd > 0)
102 {
103 if(mbtk_http_close(session->sock_fd))
104 {
105 LOGE("mbtk_http_close() fail.");
106 return -1;
107 }
108 session->sock_fd = -1;
109 }
110
111 session->state = HTTP_SESSION_STATE_NON;
112
113 return 0;
114 }
115
116 return -1;
117}
118
119
120static bool http_handle_check(int handle_id)
121{
122 if(handle_id < 0 || handle_id >= HTTP_HANDLE_MAX
123 || http_handles[handle_id].id < 0)
124 {
125 return FALSE;
126 }
127
128 return TRUE;
129}
130
131static bool http_session_check(int handle_id, int session_id)
132{
133 if(handle_id < 0 || handle_id >= HTTP_HANDLE_MAX
134 || http_handles[handle_id].id < 0
135 || http_handles[handle_id].id != handle_id)
136 {
137 return FALSE;
138 }
139
140 if(session_id < 0 || session_id >= HTTP_SESSION_MAX
141 || http_handles[handle_id].session[session_id] == NULL
142 || http_handles[handle_id].session[session_id]->id != session_id)
143 {
144 return FALSE;
145 }
146
147 return TRUE;
148}
149
150static bool http_is_space_char(char ch)
151{
152 if(ch == ' ' || ch == '\r' || ch == '\t' || ch == '\n')
153 return TRUE;
154
155 return FALSE;
156}
157
158static bool http_str_empty(char *str)
159{
160 if(str == NULL || strlen(str) == 0)
161 return TRUE;
162
163 return FALSE;
164}
165
166
167static int http_url_parse
168(
169 void* url,
170 void *host,
171 void *uri,
172 int *port,
173 bool *is_ssl
174)
175{
176 if(strlen(url) == 0)
177 {
178 return -1;
179 }
180 char *url_ptr = (char*)url;
181 char *host_ptr = (char*)host;
182
183 LOGI("URL[%d]:%s",strlen(url_ptr),url_ptr);
184
185 if(!memcmp(url_ptr,"https://",8))
186 {
187 *is_ssl = TRUE;
188 url_ptr += 8;
189 }
190 else if(!memcmp(url_ptr,"http://",7))
191 {
192 *is_ssl = FALSE;
193 url_ptr += 7;
194 }
195 else
196 {
197 *is_ssl = FALSE;
198 }
199
200 // ptr point to host.
201 while(*url_ptr)
202 {
203 if(*url_ptr == ':' || *url_ptr == '/') // Host end
204 break;
205 if(http_is_space_char(*url_ptr))
206 {
207 url_ptr++;
208 continue;
209 }
210 *host_ptr++ = *url_ptr++;
211 }
212
213 // "www.baidu.com"
214 if(*url_ptr == '\0') // No port and uri
215 {
216 if(*is_ssl)
217 {
218 *port = MBTK_HTTPS_PORT_DEF;
219 }
220 else
221 {
222 *port = MBTK_HTTP_PORT_DEF;
223 }
224 memcpy(uri,"/",1);
225
226 LOGI("HTTP parse success:'%s','%s', %d, %d",(char*)host,(char*)uri,*port,*is_ssl);
227 return 0;
228 }
229 else
230 {
231 //LOGI("Host end with:%x",*url_ptr);
232 if(*url_ptr == ':') // Port exist.
233 {
234 *port = atoi(url_ptr + 1);
235
236 // Point to '/' or NULL
237 while(*url_ptr && *url_ptr != '/')
238 {
239 url_ptr++;
240 }
241
242 // "www.baidu.com:80"
243 if(*url_ptr == '\0') // No uri
244 {
245 if(*port == 0)
246 {
247 if(*is_ssl)
248 {
249 *port = MBTK_HTTPS_PORT_DEF;
250 }
251 else
252 {
253 *port = MBTK_HTTP_PORT_DEF;
254 }
255 }
256 memcpy(uri,"/",1);
257
258 LOGI("HTTP parse success:'%s','%s', %d, %d",(char*)host,(char*)uri,*port,*is_ssl);
259 return 0;
260 }
261 }
262
263 // "www.baidu.com/xxx" or "www.baidu.com:80/xxx"
264 // Now,url_ptr point to '/'
265 if(*url_ptr != '/')
266 {
267 LOGE("URI must start with '/'.");
268 return -1;
269 }
270
271 //LOGI("URL3[%d]:%s",strlen(url_ptr),url_ptr);
272
273 memcpy(uri,url_ptr,strlen(url_ptr));
274
275 if(*port == 0)
276 {
277 if(*is_ssl)
278 {
279 *port = MBTK_HTTPS_PORT_DEF;
280 }
281 else
282 {
283 *port = MBTK_HTTP_PORT_DEF;
284 }
285 }
286
287 LOGI("HTTP parse success:'%s','%s', %d, %d",(char*)host,(char*)uri,*port,*is_ssl);
288 return 0;
289 }
290}
291
292static int http_session_req_head_add(mbtk_http_session_t *session,bool replace,
293 char *name, char *value)
294{
295 if(session == NULL || value == NULL)
296 return -1;
297
298 LOGI("Add request header - %s:%s",name,value);
299
300 int i = 0;
301 while(i < HTTP_REQUEST_HEADER_MAX)
302 {
303 if(session->req.req_h[i]
304 && !strncasecmp(session->req.req_h[i]->name,name,strlen(name))) // Is change value
305 {
306 break;
307 }
308 i++;
309 }
310
311 if(i == HTTP_REQUEST_HEADER_MAX) // Should add new header.
312 {
313 i = 0;
314 while(i < HTTP_REQUEST_HEADER_MAX)
315 {
316 if(session->req.req_h[i] == NULL) // Find NULL request.
317 {
318 session->req.req_h[i] = (mbtk_http_header_t*)malloc(sizeof(mbtk_http_header_t));
319 if(session->req.req_h[i] == NULL)
320 {
321 LOGE("malloc() fail.");
322 return -1;
323 }
324
325 memset(session->req.req_h[i],0x0,sizeof(mbtk_http_header_t));
326 memcpy(session->req.req_h[i]->name, name, strlen(name));
327 session->req.req_h[i]->value = NULL;
328 session->req.header_cnt++;
329 break;
330 }
331 i++;
332 }
333 }
334 else // Is change value
335 {
336 if(!replace)
337 {
338 LOGW("Found this header[%s],no replace.",name);
339 return 0;
340 }
341 }
342
343 if(i == HTTP_REQUEST_HEADER_MAX)
344 {
345 LOGE("Request header is full.");
346 return -1;
347 }
348
349 if(session->req.req_h[i]->value)
350 {
351 free(session->req.req_h[i]->value);
352 }
353 session->req.req_h[i]->value = (char*)malloc(strlen(value) + 1);
354 if(session->req.req_h[i]->value == NULL)
355 {
356 LOGE("malloc() fail.");
357 return -1;
358 }
359 memset(session->req.req_h[i]->value,0x0,strlen(value) + 1);
360 memcpy(session->req.req_h[i]->value,value,strlen(value));
361
362 return 0;
363}
364
365#if 0
366static int http_session_rsp_head_add(mbtk_http_session_t *session,
367 char *name, char *value)
368{
369 if(session == NULL || value == NULL)
370 return -1;
371
372 int i = 0;
373 while(i < HTTP_REQUEST_HEADER_MAX)
374 {
375 if(session->rsp.rsp_h[i] == NULL) // Find NULL request.
376 {
377 session->rsp.rsp_h[i] = (mbtk_http_header_t*)malloc(sizeof(mbtk_http_header_t));
378 if(session->rsp.rsp_h[i] == NULL)
379 {
380 LOGE("malloc() fail.");
381 return -1;
382 }
383
384 memcpy(session->rsp.rsp_h[i]->name,name,strlen(name));
385 session->rsp.rsp_h[i]->value = (char*)malloc(strlen(value) + 1);
386 if(session->rsp.rsp_h[i]->value == NULL)
387 {
388 LOGE("malloc() fail.");
389 return -1;
390 }
391 memset(session->rsp.rsp_h[i]->value,0x0,strlen(value) + 1);
392 memcpy(session->rsp.rsp_h[i]->value,value,strlen(value));
393
394 session->rsp.header_cnt++;
395 return 0;
396 }
397 i++;
398 }
399
400 return -1;
401}
402#endif
403
404static char* http_option_str_get(mbtk_http_option_enum option)
405{
406 switch(option)
407 {
408 case HTTP_OPTION_HEAD:
409 return "HEAD";
410 case HTTP_OPTION_GET:
411 return "GET";
412 case HTTP_OPTION_POST:
413 return "POST";
414 case HTTP_OPTION_PUT:
415 return "PUT";
416 case HTTP_OPTION_DELETE:
417 return "DELETE";
418 case HTTP_OPTION_OPTIONS:
419 return "OPTIONS";
420 case HTTP_OPTION_TRACE:
421 return "TRACE";
422 case HTTP_OPTION_CONNECT:
423 return "CONNECT";
424 case HTTP_OPTION_LINK:
425 return "LINK";
426 case HTTP_OPTION_UNLINK:
427 return "UNLINK";
428 default:
429 return "";
430 }
431}
432
433static char* http_version_str_get(mbtk_http_version_enum version)
434{
435 switch(version)
436 {
437 case HTTP_VERSION_1_0:
438 return "1.0";
439 case HTTP_VERSION_1_1:
440 return "1.1";
441 case HTTP_VERSION_2:
442 return "2";
443 case HTTP_VERSION_3:
444 return "3";
445 default:
446 return "";
447 }
448}
449
450static char* http_header_find(mbtk_http_session_t *session,char* name)
451{
452 int i = 0;
453 while(i < HTTP_REQUEST_HEADER_MAX)
454 {
455 if(session->req.req_h[i] &&
456 !strncasecmp(session->req.req_h[i]->name,name,strlen(name)))
457 {
458 return session->req.req_h[i]->value;
459 }
460
461 i++;
462 }
463 return NULL;
464}
465
466static int http_header_str_get(mbtk_http_header_t *header,char *header_str,int header_str_len)
467{
468 if(header == NULL || header->value == NULL
469 || header_str == NULL)
470 return 0;
471
472 int len = 0;
473 len = snprintf(header_str,header_str_len,"%s: %s\r\n",
474 header->name, header->value);
475
476 return len;
477}
478
479static mbtk_http_version_enum http_version_get_by_str(char *version_str)
480{
481 if(!memcmp(version_str,"1.0",3))
482 return HTTP_VERSION_1_0;
483 else if(!memcmp(version_str,"1.1",3))
484 return HTTP_VERSION_1_1;
485 else if(!memcmp(version_str,"2",1))
486 return HTTP_VERSION_2;
487 else if(!memcmp(version_str,"3",1))
488 return HTTP_VERSION_3;
489 else
490 return HTTP_VERSION_1_1;
491}
492
493static int http_header_read(mbtk_http_session_t *session)
494{
495#define BUFFER_SIZE 2048
496 char line[BUFFER_SIZE];
497 char *ptr = NULL;
498 int len = 0;
499 while((len = mbtk_http_read_line(session->sock_fd,line,BUFFER_SIZE)) > 0)
500 {
501 if(!memcmp(line,"\r\n",2))
502 {
503 LOGD("Read empty line.");
504 break;
505 }
LUOJian1926e372023-10-10 14:10:12 +0800506
liubin281ac462023-07-19 14:22:54 +0800507 // Delete "\r\n"
508 ptr = line + len - 1; // Point to last char.
509 while(http_is_space_char(*ptr))
510 {
511 *ptr = '\0';
512 len--;
513 ptr--;
514 }
515
516 LOGV("LINE:%s",line);
LUOJian99f31df2023-09-28 17:03:24 +0800517
LUOJian1926e372023-10-10 14:10:12 +0800518 if(http_handles[session->handle_id].show_rsp_header &&
519 http_handles[session->handle_id].data_cb)
520 {
521 http_handles[session->handle_id].data_cb(session->id,
522 MBTK_HTTP_DATA_HEADER,line,len);
523 }
liubin281ac462023-07-19 14:22:54 +0800524
525 if(!memcmp(line,"HTTP/",5)) // "HTTP/1.1 200 OK"
526 {
527 session->rsp.state_code = atoi(line + 9);
528 session->rsp.version = http_version_get_by_str(line + 5);
529 }
530 else // Is response header item.
531 {
532 if(!strncasecmp(line,"Content-Length",14))
533 {
534 ptr = line + 14;
535 while(ptr && !isdigit(*ptr))
536 {
537 ptr++;
538 }
539
540 if(ptr)
541 {
542 session->rsp.content_length = atol(ptr);
543 }
544 }
545 else if(!strncasecmp(line,"Transfer-Encoding",17))
546 {
547 ptr = line + 17;
548 while(ptr && !isalpha(*ptr))
549 {
550 ptr++;
551 }
552
553 if(ptr && !memcmp(ptr,"chunked",7))
554 {
555 session->rsp.is_chunked = TRUE;
556 }
557 }
558 }
559 }
560#undef BUFFER_SIZE
561
562 LOGD("RSP:HTTP/%s %d, is_chunked:%d,Content-Length:%d",http_version_str_get(session->rsp.version),
563 session->rsp.state_code,session->rsp.is_chunked,session->rsp.content_length);
564
565 return 0;
566}
567
568static int http_session_start_write(mbtk_http_session_t *session)
569{
570 LOGI("Start HTTP write.");
571
572#define BUFFER_SIZE 1024
573 session->state = HTTP_SESSION_STATE_WRITE_HEADER;
574 char buff[BUFFER_SIZE];
575 int len = 0;
576 int index = 0;
577 len += snprintf(buff + len,BUFFER_SIZE - len,"%s %s HTTP/%s\r\n",
578 http_option_str_get(session->option),
579 session->uri,
580 http_version_str_get(session->version));
581
582 // if no set "Host",should set default host.
583 char *host = http_header_find(session,"Host");
584 if(!host)
585 {
586 len += snprintf(buff + len,BUFFER_SIZE - len,"Host: %s\r\n", session->host);
587 }
588
589 if(mbtk_http_write(session->sock_fd,buff,len) != len)
590 {
591 LOGE("mbtk_http_write() fail.");
592 return -1;
593 }
594
595 char header_str[BUFFER_SIZE];
596 int header_str_len = 0;
597 while(index < HTTP_REQUEST_HEADER_MAX)
598 {
599 if(session->req.req_h[index] &&
600 (header_str_len = http_header_str_get(session->req.req_h[index], header_str, BUFFER_SIZE)) > 0)
601 {
602 if(mbtk_http_write(session->sock_fd,header_str,header_str_len) != header_str_len)
603 {
604 LOGE("mbtk_http_write() fail.");
605 return -1;
606 }
607 }
608 index++;
609 }
610
611 // Write request header success.
612 LOGI("HTTP write header complete.");
613
614#undef BUFFER_SIZE
615
616 // Write "\r\n"
617 if(mbtk_http_write(session->sock_fd,"\r\n",2) != 2)
618 {
619 LOGE("mbtk_http_write() fail.");
620 return -1;
621 }
622
623 LOGI("Start write HTTPsession->option. %d", session->option);
624 if(session->option == HTTP_OPTION_POST)
625 {
626 session->state = HTTP_SESSION_STATE_WRITE_CONTENT;
627 LOGI("Start write HTTP content data.");
628
629 if(session->req.content && session->req.content_len > 0)
630 {
631 if(mbtk_http_write(session->sock_fd,session->req.content,session->req.content_len) != session->req.content_len)
632 {
633 LOGE("mbtk_http_write() fail.");
634 return -1;
635 }
636
637 session->state = HTTP_SESSION_STATE_WRITE_END;
638 }
639 }
640 else
641 {
642 session->state = HTTP_SESSION_STATE_WRITE_END;
643
644 LOGI("HTTP write complete.");
645 }
646 return 0;
647}
648
649static int http_session_read_by_chunk(mbtk_http_session_t *session)
650{
651#undef BUFFER_SIZE
652#define BUFFER_SIZE 2048
653 http_chunk_code chunk_code;
654 http_chunker_t chunker;
655 char read_buf[BUFFER_SIZE + 1];
656 int read_len = 0;
657 char chunk_buf[BUFFER_SIZE + 1];
LUOJian1926e372023-10-10 14:10:12 +0800658 int chunk_len;
liubin281ac462023-07-19 14:22:54 +0800659 http_chunk_init(&chunker);
660 while(TRUE)
661 {
662 read_len = mbtk_http_read(session->sock_fd,read_buf,BUFFER_SIZE,3000);
663 //read_len = mbtk_http_read_line(session->sock_file,read_buf,BUFFER_SIZE);
664 if(read_len <= 0)
665 {
666 LOGE("Read fail.");
667 return -1;
668 }
669
670 chunk_code = http_chunk_parse(&chunker, read_buf, read_len, chunk_buf, &chunk_len);
671 if(chunk_code > CHUNKE_OK) // Fail.
672 {
673 LOGE("http_chunk_parse() fail[err - %d].",chunk_code);
674 return -1;
675 }
676
677 LOGD("Read chunk_len:%d",chunk_len);
678 chunk_buf[chunk_len] = '\0';
679
LUOJian1926e372023-10-10 14:10:12 +0800680 if(http_handles[session->handle_id].data_cb)
681 http_handles[session->handle_id].data_cb(session->id,
682 MBTK_HTTP_DATA_CONTENT,chunk_buf,chunk_len);
liubin281ac462023-07-19 14:22:54 +0800683
684 if(CHUNKE_STOP == chunk_code)
685 {
686 if(http_handles[session->handle_id].data_cb)
687 http_handles[session->handle_id].data_cb(session->id,
688 MBTK_HTTP_DATA_COMPLETE,NULL,0);
689
690 break;
691 }
692 }
693
694 LOGV("Chunk read success.");
695
696 return 0;
697}
698
699static int http_session_read_by_length(mbtk_http_session_t *session)
700{
701#undef BUFFER_SIZE
702#define BUFFER_SIZE 2048
703 char read_buf[BUFFER_SIZE + 1];
704 int read_len = 0;
705 int64 read_count = 0;
706 while(TRUE)
707 {
708 memset(read_buf,0x0,BUFFER_SIZE + 1);
709 read_len = mbtk_http_read(session->sock_fd,read_buf,BUFFER_SIZE,3000);
710 if(read_len <= 0)
711 {
712 LOGE("Read fail.");
713 return -1;
714 }
715
b.liubcf86c92024-08-19 19:48:28 +0800716
liubin281ac462023-07-19 14:22:54 +0800717 if(read_count + read_len >= session->rsp.content_length) // Read data complete.
718 {
719 if(http_handles[session->handle_id].data_cb)
720 {
721 http_handles[session->handle_id].data_cb(session->id,
722 MBTK_HTTP_DATA_CONTENT,read_buf,session->rsp.content_length - read_count);
b.liubcf86c92024-08-19 19:48:28 +0800723
liubin281ac462023-07-19 14:22:54 +0800724 http_handles[session->handle_id].data_cb(session->id,
725 MBTK_HTTP_DATA_COMPLETE,NULL,0);
726 }
727 break;
728 }
729
LUOJian1926e372023-10-10 14:10:12 +0800730 if(http_handles[session->handle_id].data_cb)
731 http_handles[session->handle_id].data_cb(session->id,
732 MBTK_HTTP_DATA_CONTENT,read_buf,read_len);
liubin281ac462023-07-19 14:22:54 +0800733
734 read_count += read_len;
735 }
736
737 return 0;
738}
739
740static int http_session_read_by_general(mbtk_http_session_t *session)
741{
742#undef BUFFER_SIZE
743#define BUFFER_SIZE 2048
744 char read_buf[BUFFER_SIZE + 1];
745 int read_len = 0;
746 while(TRUE)
747 {
748 read_len = mbtk_http_read(session->sock_fd,read_buf,BUFFER_SIZE,1000);
749 if(read_len <= 0)
750 {
751 if(read_len == -2 || read_len == 0) // Timeout or end
752 break;
753
754 LOGW("Read end[read_len - %d].",read_len);
755 //return -1;
756 break;
757 }
LUOJian1926e372023-10-10 14:10:12 +0800758
liubin281ac462023-07-19 14:22:54 +0800759 read_buf[read_len] = '\0';
760
LUOJian1926e372023-10-10 14:10:12 +0800761 if(http_handles[session->handle_id].data_cb)
762 http_handles[session->handle_id].data_cb(session->id,
763 MBTK_HTTP_DATA_CONTENT,read_buf,read_len);
liubin281ac462023-07-19 14:22:54 +0800764 }
765
766 if(http_handles[session->handle_id].data_cb)
767 http_handles[session->handle_id].data_cb(session->id,
768 MBTK_HTTP_DATA_COMPLETE,NULL,0);
769
LUOJian99f31df2023-09-28 17:03:24 +0800770
liubin281ac462023-07-19 14:22:54 +0800771 return 0;
772}
773
774static int http_session_start_read(mbtk_http_session_t *session)
775{
776 LOGI("Start HTTP read.");
777 int result = 0;
778// usleep(500000);
779 session->state = HTTP_SESSION_STATE_READ_HEADER;
780 if(http_header_read(session))
781 {
782 result = -1;
783 goto read_end;
784 }
785
786 if(session->option != HTTP_OPTION_HEAD)
787 {
788 session->state = HTTP_SESSION_STATE_READ_CONTENT;
789 if(session->rsp.is_chunked)
790 {
791 if(http_session_read_by_chunk(session))
792 {
LUOJian99f31df2023-09-28 17:03:24 +0800793 LOGE("http_session_read_by_chunk fail.");
liubin281ac462023-07-19 14:22:54 +0800794 result = -1;
795 goto read_end;
796 }
797 }
798 else if(session->rsp.content_length > 0)
799 {
800 if(http_session_read_by_length(session))
801 {
LUOJian99f31df2023-09-28 17:03:24 +0800802 LOGE("http_session_read_by_length fail.");
liubin281ac462023-07-19 14:22:54 +0800803 result = -1;
804 goto read_end;
805 }
806 }
807 else
808 {
809 if(http_session_read_by_general(session))
810 {
LUOJian99f31df2023-09-28 17:03:24 +0800811 LOGE("http_session_read_by_general fail.");
liubin281ac462023-07-19 14:22:54 +0800812 result = -1;
813 goto read_end;
814 }
815 }
816 }
817 else
818 {
819 if(http_handles[session->handle_id].data_cb)
820 http_handles[session->handle_id].data_cb(session->id,
821 MBTK_HTTP_DATA_COMPLETE,NULL,0);
822 }
823
824read_end:
825 session->state = HTTP_SESSION_STATE_READ_END;
826
827 LOGI("HTTP request complete[result - %d].",result);
828 if(http_session_close(session))
829 {
830 return -1;
831 }
832
833#if 0
834 // Free session after HTTP request complete.
835 http_session_free(session);
836 http_handles[handle_id].session[session_id] = NULL;
837 http_handles[handle_id].session_cnt--;
838#endif
839
840 return result;
841}
842
843static bool http_session_req_check(mbtk_http_session_t *session)
844{
845 if(session == NULL || session->port == 0 ||
846 strlen(session->host) == 0)
847 {
848 LOGE("Session not set host or port.");
849 return FALSE;
850 }
851
852 if(session->option != HTTP_OPTION_HEAD &&
853 session->option != HTTP_OPTION_POST &&
854 session->option != HTTP_OPTION_GET)
855 {
856 LOGE("Only support HEAD/GET/POST");
857 return FALSE;
858 }
859
860#if 0
861 if(session->version != HTTP_VERSION_1_0 &&
862 session->version != HTTP_VERSION_1_1)
863 {
864 LOGE("Only support HTTP 1.0/1.1");
865 return FALSE;
866 }
867#endif
868
869 if(session->option == HTTP_OPTION_POST)
870 {
871 char *value = NULL;
872 value = http_header_find(session, "Content-Length");
873 if(!value)
874 {
875 LOGE("POST must set 'Content-Length'");
876 return FALSE;
877 }
878 if(session->req.content_len != atoi(value))
879 {
880 LOGE("POST 'Content-Length' error.");
881 return FALSE;
882 }
883
884 value = http_header_find(session, "Content-Type");
885 if(!value)
886 {
887 LOGE("POST must set 'Content-Type'");
888 return FALSE;
889 }
890 }
891
892 return TRUE;
893}
894
895/*************************************************************
896 Public Function Definitions
897*************************************************************/
898int mbtk_http_handle_get(bool show_rsp_header,mbtk_http_data_callback_func data_cb)
899{
900 int index = 0;
901 int i = 0;
902 for(; index < HTTP_HANDLE_MAX; index++)
903 {
904 if(http_handles[index].id < 0) // Find free handle
905 {
906 break;
907 }
908 }
909
910 if(index == HTTP_HANDLE_MAX)
911 {
912 LOGE("HTTP Handle is full.");
913 return -1;
914 }
915
916 memset(&(http_handles[index]),0x0,sizeof(mbtk_http_handle_t));
917 http_handles[index].id = index;
918 http_handles[index].show_rsp_header = show_rsp_header;
919 http_handles[index].data_cb = data_cb;
920 http_handles[index].session_cnt = 0;
921 for(i = 0; i < HTTP_SESSION_MAX; i++)
922 {
923 http_handles[index].session[i] = NULL;
924 }
925
926 if(mbtk_http_init())
927 {
928 LOGE("mbtk_http_init() fail.");
929 return -1;
930 }
931
932 return http_handles[index].id;
933}
934
935int mbtk_http_handle_free(int handle_id)
936{
937 int i = 0;
938 if(!http_handle_check(handle_id))
939 {
940 LOGE("Handle error.");
941 return -1;
942 }
943
944 http_handles[handle_id].id = -1;
945 http_handles[handle_id].data_cb = NULL;
946 if(http_handles[handle_id].session_cnt > 0)
947 {
948 for(i = 0; i < HTTP_SESSION_MAX; i++)
949 {
950 if(http_handles[handle_id].session[i] != NULL)
951 {
952 if(http_handles[handle_id].session[i]->state != HTTP_SESSION_STATE_NON)
953 {
954 if(http_session_close(http_handles[handle_id].session[i]))
955 {
956 return -1;
957 }
958 }
959
960 http_session_free(http_handles[handle_id].session[i]);
961 http_handles[handle_id].session[i] = NULL;
962 }
963 }
964
965 http_handles[handle_id].session_cnt = 0;
966 }
967
968 if(mbtk_http_deinit())
969 {
970 LOGE("mbtk_http_deinit() fail.");
971 return -1;
972 }
973
974 return 0;
975}
976
977int mbtk_http_session_create(int handle_id, mbtk_http_option_enum option,
978 mbtk_http_version_enum version)
979{
980 int handle_index = 0;
981 int session_index = 0;
982 if(!http_handle_check(handle_id))
983 {
984 LOGE("Handle error.");
985 return -1;
986 }
987
988 for(; handle_index < HTTP_HANDLE_MAX; handle_index++)
989 {
990 if(http_handles[handle_index].id == handle_id) // Find handle
991 {
992 break;
993 }
994 }
995
996 if(handle_index == HTTP_HANDLE_MAX)
997 {
998 LOGE("No found handle[handle - %d].",handle_id);
999 return -1;
1000 }
1001
1002 if(http_handles[handle_index].session_cnt >= HTTP_SESSION_MAX)
1003 {
1004 LOGE("Session is full.");
1005 return -1;
1006 }
1007
1008 for(; session_index < HTTP_SESSION_MAX; session_index++)
1009 {
1010 if(http_handles[handle_index].session[session_index] == NULL) // Find first NULL session
1011 {
1012 break;
1013 }
1014 }
1015
1016 if(session_index == HTTP_SESSION_MAX)
1017 {
1018 LOGE("Session is full.");
1019 return -1;
1020 }
1021
1022 mbtk_http_session_t* session = (mbtk_http_session_t*)malloc(sizeof(mbtk_http_session_t));
1023 if(session == NULL)
1024 {
1025 LOGE("malloc() fail.");
1026 return -1;
1027 }
1028 memset(session,0x0,sizeof(mbtk_http_session_t));
1029 session->sock_fd = -1;
LUOJian99f31df2023-09-28 17:03:24 +08001030 session->file_fd = -1;
liubin281ac462023-07-19 14:22:54 +08001031 session->handle_id = handle_id;
1032 session->id = session_index;
1033 session->state = HTTP_SESSION_STATE_NON;
1034 session->is_ssl = FALSE;
LUOJian5f18afe2023-10-09 10:23:34 +08001035 session->ingnore_cert = TRUE;
liubin281ac462023-07-19 14:22:54 +08001036 session->version = version;
1037 session->option = option;
1038 session->req.content_len = 0;
1039 session->req.content_len_send = 0;
1040 session->rsp.is_chunked = FALSE;
1041 session->rsp.content_length = 0;
1042 session->rsp.header_cnt = 0;
1043 http_handles[handle_index].session[session_index] = session;
1044 http_handles[handle_index].session_cnt++;
1045
1046 return session->id;
1047}
1048
1049int mbtk_http_session_option_reset(int handle_id, int session_id, mbtk_http_option_enum option)
1050{
1051 if(!http_session_check(handle_id,session_id))
1052 {
1053 LOGE("Session error.");
1054 return -1;
1055 }
1056
1057 mbtk_http_session_t *session = http_handles[handle_id].session[session_id];
1058 if(session->state != HTTP_SESSION_STATE_NON)
1059 {
1060 LOGE("Session state error.[%d]",session->state);
1061 return -1;
1062 }
1063
1064 session->option = option;
1065 return 0;
1066}
1067
LUOJian99f31df2023-09-28 17:03:24 +08001068
LUOJian5f18afe2023-10-09 10:23:34 +08001069int mbtk_http_session_ingnore_cert_set(int handle_id, int session_id, bool ingnore_cert)
1070{
1071 if(!http_session_check(handle_id,session_id))
1072 {
1073 LOGE("Session error.");
1074 return -1;
1075 }
1076
1077 mbtk_http_session_t *session = http_handles[handle_id].session[session_id];
1078
1079 session->ingnore_cert = ingnore_cert;
1080
1081 LOGE("session->ingnore_cert:%d, ingnore_cert:%d\n", session->ingnore_cert, ingnore_cert);
1082 return 0;
1083}
1084
1085
liubin281ac462023-07-19 14:22:54 +08001086int mbtk_http_session_free(int handle_id,int session_id)
1087{
1088 if(!http_session_check(handle_id,session_id))
1089 {
1090 LOGE("Session error.");
1091 return -1;
1092 }
1093
1094 mbtk_http_session_t *session = http_handles[handle_id].session[session_id];
1095 if(session->state != HTTP_SESSION_STATE_NON)
1096 {
1097 if(http_session_close(session))
1098 {
1099 return -1;
1100 }
1101 }
1102
1103 http_session_free(session);
1104 http_handles[handle_id].session[session_id] = NULL;
1105 http_handles[handle_id].session_cnt--;
1106 return 0;
1107}
1108
1109int mbtk_http_session_url_set(int handle_id,int session_id,void *url)
1110{
1111 if(!http_session_check(handle_id,session_id))
1112 {
1113 LOGE("Session error.");
1114 return -1;
1115 }
1116
1117 mbtk_http_session_t *session = http_handles[handle_id].session[session_id];
1118 if(session->state == HTTP_SESSION_STATE_NON)
1119 return http_url_parse(url, session->host,session->uri,&(session->port),&(session->is_ssl));
1120 else
1121 {
1122 LOGE("Currenr session is process[state - %d].",session->state);
1123 return -1;
1124 }
1125}
1126
1127int mbtk_http_session_head_add(int handle_id,int session_id,
1128 char *name, char *value)
1129{
1130 if(!http_session_check(handle_id,session_id))
1131 {
1132 LOGE("Session error.");
1133 return -1;
1134 }
1135
1136 if(http_str_empty(name) || http_str_empty(value))
1137 {
1138 LOGE("Param error.");
1139 return -1;
1140 }
1141
1142 mbtk_http_session_t *session = http_handles[handle_id].session[session_id];
1143 if(session->state == HTTP_SESSION_STATE_NON)
1144 {
1145 int result = http_session_req_head_add(session,TRUE,name,value);
1146 if(!result && !strncasecmp(name,"Content-Length",14))
1147 {
1148 session->req.content_len = atoi(value);
1149 }
1150 return result;
1151 }
1152 else
1153 {
1154 LOGE("Currenr session is process[state - %d].",session->state);
1155 return -1;
1156 }
1157}
1158
1159int mbtk_http_session_content_set(int handle_id,int session_id,
1160 char *content,uint32 content_len)
1161{
1162 if(!http_session_check(handle_id,session_id))
1163 {
1164 LOGE("Session error.");
1165 return -1;
1166 }
1167
1168 if(content_len <= 0 || content_len > HTTP_CONTENT_LEN_MAX)
1169 {
1170 LOGE("Content lenght error[%d].",content_len);
1171 return -1;
1172 }
1173
1174 mbtk_http_session_t *session = http_handles[handle_id].session[session_id];
1175 if(session->state == HTTP_SESSION_STATE_NON)
1176 {
1177 if(session->option != HTTP_OPTION_POST)
1178 {
1179 LOGE("Content only for post.");
1180 return -1;
1181 }
1182
1183 if(session->req.content)
1184 {
1185 free(session->req.content);
1186 session->req.content_len = 0;
1187 }
1188
1189 session->req.content = (char*)malloc(content_len);
1190 if(session->req.content == NULL)
1191 {
1192 LOGE("malloc() fail.");
1193 return -1;
1194 }
1195
1196 char *content_type = NULL;
1197 if(strlen(content) == content_len) //
1198 {
1199 content_type = "text/plain";
1200 }
1201 else
1202 {
1203 content_type = "application/octet-stream";
1204 }
1205
1206 if(http_session_req_head_add(session, FALSE, "Content-Type", content_type))
1207 {
1208 LOGE("Set 'Content-Type' fail.");
1209 return -1;
1210 }
1211
1212 memcpy(session->req.content,content,content_len);
1213 session->req.content_len = content_len;
1214
1215 char len_str[20] = {0};
1216 snprintf(len_str,20,"%d",content_len);
1217 if(http_session_req_head_add(session,FALSE,"Content-Length",len_str))
1218 {
1219 LOGE("Set 'Content-Length' fail.");
1220 return -1;
1221 }
1222
1223
1224 return 0;
1225 }
1226 else
1227 {
1228 LOGE("Currenr session is process[state - %d].",session->state);
1229 return -1;
1230 }
1231}
1232
1233int mbtk_http_session_start(int handle_id,int session_id)
1234{
1235 if(!http_session_check(handle_id,session_id))
1236 {
1237 LOGE("Session error.");
1238 return -1;
1239 }
1240
1241 mbtk_http_session_t *session = http_handles[handle_id].session[session_id];
1242 if(session->state == HTTP_SESSION_STATE_NON)
1243 {
1244 if(!http_session_req_check(session))
1245 {
1246 LOGE("http_session_req_check() fail.");
1247 return -1;
1248 }
1249
1250 // Must set "Connection" for post.
1251 if(session->option == HTTP_OPTION_POST)
1252 {
1253 if(http_session_req_head_add(session,FALSE,"Connection","KeepAlive"))
1254 {
1255 LOGE("Set 'Content-Length' fail.");
1256 return -1;
1257 }
1258 }
1259
1260 LOGI("HTTP request start.");
1261 LOGI("host:%s, port:%d, uri:%s",session->host,session->port,session->uri);
b.liubcf86c92024-08-19 19:48:28 +08001262 LOGI("is_ssl:%d,ingnore_cert:%d, version:%d, option:%d, content_len:%d",session->is_ssl,
LUOJian5f18afe2023-10-09 10:23:34 +08001263 session->ingnore_cert, session->version,session->option,session->req.content_len);
liubin281ac462023-07-19 14:22:54 +08001264
LUOJian5f18afe2023-10-09 10:23:34 +08001265 int sock_fd = mbtk_http_open(session->is_ssl,session->ingnore_cert,session->host,session->port);
1266
liubin281ac462023-07-19 14:22:54 +08001267 if(sock_fd < 0)
1268 {
LUOJian5f18afe2023-10-09 10:23:34 +08001269 LOGE("mbtk_http_open() fail.");
liubin281ac462023-07-19 14:22:54 +08001270 return -1;
1271 }
1272 session->sock_fd = sock_fd;
1273// int fd = mbtk_sock_fd_get(sock_fd);
1274// if(fd < 0) {
1275// LOGE("mbtk_sock_fd_get() fail.");
1276// return -1;
1277// }
1278 // session->sock_file = fdopen(sock_fd,"r");
1279 session->state = HTTP_SESSION_STATE_CONN;
1280
1281// if(!session->sock_file) {
1282// LOGE("fdopen() fail.");
1283// return -1;
1284// }
1285
1286 LOGI("HTTP connected.");
1287
1288 if(http_session_start_write(session))
1289 {
1290 return -1;
1291 }
1292
1293 if(session->state == HTTP_SESSION_STATE_WRITE_END)
1294 {
1295 if(http_session_start_read(session))
1296 {
1297 return -1;
1298 }
1299 }
1300 else
1301 {
1302 LOGI("Waitting post content data...");
1303 }
1304
1305 return 0;
1306 }
1307 else
1308 {
1309 LOGE("Currenr session is process[state - %d].",session->state);
1310 return -1;
1311 }
1312}
1313
1314int mbtk_http_session_content_send(int handle_id,int session_id,
1315 char *data,int data_len)
1316{
1317 if(!http_session_check(handle_id,session_id))
1318 {
1319 LOGE("Session error.");
1320 return -1;
1321 }
1322
1323 if(data_len <= 0 || data_len > HTTP_CONTENT_LEN_MAX)
1324 {
1325 LOGE("Content lenght error[%d].",data_len);
1326 return -1;
1327 }
1328
1329 LOGV("Post send:%d - %s",data_len,data);
1330
1331 mbtk_http_session_t *session = http_handles[handle_id].session[session_id];
1332 if(session->state == HTTP_SESSION_STATE_WRITE_CONTENT)
1333 {
1334 if(session->option != HTTP_OPTION_POST)
1335 {
1336 LOGE("Content only for post.");
1337 return -1;
1338 }
1339
1340 if(session->req.content || session->req.content_len <= 0)
1341 {
1342 LOGE("This post not spit package.");
1343 return -1;
1344 }
1345
1346 // Discard excess data.
1347 if(session->req.content_len_send + data_len > session->req.content_len)
1348 data_len = session->req.content_len - session->req.content_len_send;
1349
1350 if(data_len != mbtk_http_write(session->sock_fd,data,data_len))
1351 {
1352 return -1;
1353 }
1354
1355 session->req.content_len_send += data_len;
1356
1357 LOGI("HTTP post data send: %d / %d",session->req.content_len_send,
1358 session->req.content_len);
1359
1360 // Post data send complete.
1361 if(session->req.content_len_send >= session->req.content_len)
1362 {
1363 session->state = HTTP_SESSION_STATE_WRITE_END;
1364
1365 LOGI("HTTP write complete.");
1366 if(http_session_start_read(session))
1367 {
1368 return -1;
1369 }
1370 }
1371
1372 return 0;
1373 }
1374 else
1375 {
1376 LOGE("Currenr session state error[%d].",session->state);
1377 return -1;
1378 }
1379}
1380
1381const mbtk_http_session_t* mbtk_http_session_get(int handle_id,int session_id)
1382{
1383 if(!http_session_check(handle_id,session_id))
1384 {
1385 LOGE("Session error.");
1386 return NULL;
1387 }
1388
1389 return http_handles[handle_id].session[session_id];
1390}
LUOJian99f31df2023-09-28 17:03:24 +08001391
b.liubcf86c92024-08-19 19:48:28 +08001392void mbtk_http_lib_info_print()
1393{
1394 MBTK_SOURCE_INFO_PRINT("mbtk_http_lib");
1395}
LUOJian99f31df2023-09-28 17:03:24 +08001396