/***************************************************************************************
 *
 *  IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
 *
 *  By downloading, copying, installing or using the software you agree to this license.
 *  If you do not agree to this license, do not download, install, 
 *  copy or use the software.
 *
 *  Copyright (C) 2014-2024, Happytimesoft Corporation, all rights reserved.
 *
 *  Redistribution and use in binary forms, with or without modification, are permitted.
 *
 *  Unless required by applicable law or agreed to in writing, software distributed 
 *  under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
 *  CONDITIONS OF ANY KIND, either express or implied. See the License for the specific
 *  language governing permissions and limitations under the License.
 *
****************************************************************************************/

#include "sys_inc.h"
#include "http.h"
#include "http_parse.h"
#include "http_cln.h"
#include "rfc_md5.h"
#include "sha256.h"
#include "base64.h"

/***************************************************************************************/

#ifdef HTTPS
#if __WINDOWS_OS__
#pragma comment(lib, "libcrypto.lib")
#pragma comment(lib, "libssl.lib")
#endif
#endif

/***************************************************************************************/

#define MAX_CTT_LEN     (2*1024*1024)


/***************************************************************************************/

static inline int http_isspace(int c)
{
    return c == ' ' || c == '\f' || c == '\n' || 
           c == '\r' || c == '\t' || c == '\v';
}

void http_choose_qop(char * qop, int size)
{
    char * ptr = strstr(qop, "auth");
    char * end = ptr + strlen("auth");

    if (ptr && (!*end || http_isspace(*end) || *end == ',') &&
        (ptr == qop || http_isspace(ptr[-1]) || ptr[-1] == ',')) 
    {
        strncpy(qop, "auth", size);
    } 
    else 
    {
        qop[0] = 0;
    }
}

BOOL http_get_digest_params(char * p, int len, HD_AUTH_INFO * p_auth)
{
    char word_buf[128];
    
    if (GetNameValuePair(p, len, "algorithm", word_buf, sizeof(word_buf)))
	{
		strncpy(p_auth->auth_algorithm, word_buf, sizeof(p_auth->auth_algorithm)-1);
	}	
	else
	{
		p_auth->auth_algorithm[0] = '\0';
	}
	
	if (GetNameValuePair(p, len, "realm", word_buf, sizeof(word_buf)))
	{
	    strncpy(p_auth->auth_realm, word_buf, sizeof(p_auth->auth_realm)-1);
	}
	else
	{
	    return FALSE;
	}

	if (GetNameValuePair(p, len, "nonce", word_buf, sizeof(word_buf)))
	{
	    strncpy(p_auth->auth_nonce, word_buf, sizeof(p_auth->auth_nonce)-1);
	}
	else
	{
	    return FALSE;
	}

	if (GetNameValuePair(p, len, "qop", word_buf, sizeof(word_buf)))
	{	
		strncpy(p_auth->auth_qop, word_buf, sizeof(p_auth->auth_qop)-1);
	}	
	else
	{
		p_auth->auth_qop[0] = '\0';
	}

	http_choose_qop(p_auth->auth_qop, sizeof(p_auth->auth_qop));
	
	if (GetNameValuePair(p, len, "opaque", word_buf, sizeof(word_buf)))
	{
	    p_auth->auth_opaque_flag = 1;
		strncpy(p_auth->auth_opaque, word_buf, sizeof(p_auth->auth_opaque)-1);
	}	
	else
	{
	    p_auth->auth_opaque_flag = 0;
		p_auth->auth_opaque[0] = '\0';
	}
	
	return TRUE;
}

BOOL http_get_digest_info(HTTPMSG * rx_msg, HD_AUTH_INFO * p_auth)
{
    int len;
	int	next_offset;
	char word_buf[128];
	HDRV * chap_id = NULL;
	char * p;

	p_auth->auth_response[0] = '\0';

RETRY:

    if (chap_id)
    {
        chap_id = http_find_headline_next(rx_msg, "WWW-Authenticate", chap_id);
    }
    else
    {
        chap_id = http_find_headline(rx_msg, "WWW-Authenticate");
    }
    
	if (chap_id == NULL)
	{
		return FALSE;
	}

	GetLineWord(chap_id->value_string, 0, (int)strlen(chap_id->value_string),
		word_buf, sizeof(word_buf), &next_offset, WORD_TYPE_STRING);
	if (strcasecmp(word_buf, "digest") != 0)
	{
        goto RETRY;
	}

	p = chap_id->value_string + next_offset;
	len = (int)strlen(chap_id->value_string) - next_offset;

    if (!http_get_digest_params(p, len, p_auth))
    {
        goto RETRY;
    }

    if (p_auth->auth_algorithm[0] != '\0' && 
        strncasecmp(p_auth->auth_algorithm, "MD5", 3) &&  
        strncasecmp(p_auth->auth_algorithm, "SHA-256", 7))
    {
        goto RETRY;
    }
	
	return TRUE;
}

BOOL http_calc_auth_md5_digest(HD_AUTH_INFO * p_auth, const char * method)
{
    uint8 HA1[16];
	uint8 HA2[16];
	uint8 HA3[16];
	char HA1Hex[33];
	char HA2Hex[33];
	char HA3Hex[33];
	md5_context ctx;

	md5_starts(&ctx);
	md5_update(&ctx, (uint8 *)p_auth->auth_name, strlen(p_auth->auth_name));
	md5_update(&ctx, (uint8 *)&(":"), 1);
	md5_update(&ctx, (uint8 *)p_auth->auth_realm, strlen(p_auth->auth_realm));
	md5_update(&ctx, (uint8 *)&(":"), 1);
	md5_update(&ctx, (uint8 *)p_auth->auth_pwd, strlen(p_auth->auth_pwd));
	md5_finish(&ctx, HA1);

    bin_to_hex_str(HA1, 16, HA1Hex, 33);

    if (!strcasecmp(p_auth->auth_algorithm, "MD5-sess"))
    {
        md5_starts(&ctx);
        md5_update(&ctx, (uint8 *)HA1Hex, 32);
        md5_update(&ctx, (uint8 *)&(":"), 1);
        md5_update(&ctx, (uint8 *)p_auth->auth_nonce, strlen(p_auth->auth_nonce));
        md5_update(&ctx, (uint8 *)&(":"), 1);
        md5_update(&ctx, (uint8 *)p_auth->auth_cnonce, strlen(p_auth->auth_cnonce));
        md5_finish(&ctx, HA1);

        bin_to_hex_str(HA1, 16, HA1Hex, 33);
    }
    
	md5_starts(&ctx);
	md5_update(&ctx, (uint8 *)method, strlen(method));
	md5_update(&ctx, (uint8 *)&(":"), 1);
	md5_update(&ctx, (uint8 *)p_auth->auth_uri, strlen(p_auth->auth_uri));
	md5_finish(&ctx, HA2);

	bin_to_hex_str(HA2, 16, HA2Hex, 33);

	md5_starts(&ctx);
	md5_update(&ctx, (uint8 *)HA1Hex, 32);
	md5_update(&ctx, (uint8 *)&(":"), 1);
	md5_update(&ctx, (uint8 *)p_auth->auth_nonce, strlen(p_auth->auth_nonce));
	md5_update(&ctx, (uint8 *)&(":"), 1);

	if (p_auth->auth_qop[0] != '\0') 
	{
		md5_update(&ctx, (uint8 *)p_auth->auth_ncstr, strlen(p_auth->auth_ncstr));
		md5_update(&ctx, (uint8 *)&(":"), 1);
		md5_update(&ctx, (uint8 *)p_auth->auth_cnonce, strlen(p_auth->auth_cnonce));
		md5_update(&ctx, (uint8 *)&(":"), 1);
		md5_update(&ctx, (uint8 *)p_auth->auth_qop, strlen(p_auth->auth_qop));
		md5_update(&ctx, (uint8 *)&(":"), 1);
	};
	
	md5_update(&ctx, (uint8 *)HA2Hex, 32);
	md5_finish(&ctx, HA3);

    bin_to_hex_str(HA3, 16, HA3Hex, 33);

	strcpy(p_auth->auth_response, HA3Hex);
	
	return TRUE;
}

BOOL http_calc_auth_sha256_digest(HD_AUTH_INFO * p_auth, const char * method)
{
    uint8 HA1[32];
	uint8 HA2[32];
	uint8 HA3[32];
	char HA1Hex[65];
	char HA2Hex[65];
	char HA3Hex[65];
	sha256_context ctx;

	sha256_starts(&ctx);
	sha256_update(&ctx, (uint8 *)p_auth->auth_name, strlen(p_auth->auth_name));
	sha256_update(&ctx, (uint8 *)&(":"), 1);
	sha256_update(&ctx, (uint8 *)p_auth->auth_realm, strlen(p_auth->auth_realm));
	sha256_update(&ctx, (uint8 *)&(":"), 1);
	sha256_update(&ctx, (uint8 *)p_auth->auth_pwd, strlen(p_auth->auth_pwd));
	sha256_finish(&ctx, HA1);

    bin_to_hex_str(HA1, 32, HA1Hex, 65);

    if (!strcasecmp(p_auth->auth_algorithm, "SHA-256-sess"))
    {
        sha256_starts(&ctx);
        sha256_update(&ctx, (uint8 *)HA1Hex, 64);
        sha256_update(&ctx, (uint8 *)&(":"), 1);
        sha256_update(&ctx, (uint8 *)p_auth->auth_nonce, strlen(p_auth->auth_nonce));
        sha256_update(&ctx, (uint8 *)&(":"), 1);
        sha256_update(&ctx, (uint8 *)p_auth->auth_cnonce, strlen(p_auth->auth_cnonce));
        sha256_finish(&ctx, HA1);

        bin_to_hex_str(HA1, 32, HA1Hex, 65);
    }
    
	sha256_starts(&ctx);
	sha256_update(&ctx, (uint8 *)method, strlen(method));
	sha256_update(&ctx, (uint8 *)&(":"), 1);
	sha256_update(&ctx, (uint8 *)p_auth->auth_uri, strlen(p_auth->auth_uri));
	sha256_finish(&ctx, HA2);

	bin_to_hex_str(HA2, 32, HA2Hex, 65);

	sha256_starts(&ctx);
	sha256_update(&ctx, (uint8 *)HA1Hex, 64);
	sha256_update(&ctx, (uint8 *)&(":"), 1);
	sha256_update(&ctx, (uint8 *)p_auth->auth_nonce, strlen(p_auth->auth_nonce));
	sha256_update(&ctx, (uint8 *)&(":"), 1);

	if (p_auth->auth_qop[0] != '\0') 
	{
		sha256_update(&ctx, (uint8 *)p_auth->auth_ncstr, strlen(p_auth->auth_ncstr));
		sha256_update(&ctx, (uint8 *)&(":"), 1);
		sha256_update(&ctx, (uint8 *)p_auth->auth_cnonce, strlen(p_auth->auth_cnonce));
		sha256_update(&ctx, (uint8 *)&(":"), 1);
		sha256_update(&ctx, (uint8 *)p_auth->auth_qop, strlen(p_auth->auth_qop));
		sha256_update(&ctx, (uint8 *)&(":"), 1);
	};
	
	sha256_update(&ctx, (uint8 *)HA2Hex, 64);
	sha256_finish(&ctx, HA3);

    bin_to_hex_str(HA3, 32, HA3Hex, 65);

	strcpy(p_auth->auth_response, HA3Hex);
	
	return TRUE;
}

BOOL http_calc_auth_digest(HD_AUTH_INFO * p_auth, const char * method)
{
    BOOL ret = FALSE;

    p_auth->auth_nc++;
    sprintf(p_auth->auth_ncstr, "%08X", p_auth->auth_nc);
    sprintf(p_auth->auth_cnonce, "%08X%08X", rand(), rand());
	    
    if (p_auth->auth_algorithm[0] == '\0' || 
        strncasecmp(p_auth->auth_algorithm, "MD5", 3) == 0)
    {
        ret = http_calc_auth_md5_digest(p_auth, method);
    }
    else if (strncasecmp(p_auth->auth_algorithm, "SHA-256", 7) == 0)
    {
        ret = http_calc_auth_sha256_digest(p_auth, method);
    }

    return ret;
}

int http_build_auth_msg(HTTPREQ * p_http, const char * method, char * buff, int buflen)
{
	int offset = 0;
	HD_AUTH_INFO * p_auth = &p_http->auth_info;
	
	if (p_http->auth_mode == 1)			// digest auth
    {
        http_calc_auth_digest(p_auth, method);

        offset += snprintf(buff+offset, buflen-offset, 
            "Authorization: Digest username=\"%s\", realm=\"%s\", "
            "nonce=\"%s\", uri=\"%s\", response=\"%s\"",
            p_auth->auth_name, p_auth->auth_realm, 
            p_auth->auth_nonce, p_auth->auth_uri, p_auth->auth_response);

        if (p_auth->auth_opaque_flag)
        {
            offset += snprintf(buff+offset, buflen-offset, 
                ", opaque=\"%s\"", p_auth->auth_opaque);
        }
        
        if (p_auth->auth_qop[0] != '\0')
        {
            offset += snprintf(buff+offset, buflen-offset, 
                ", qop=\"%s\", cnonce=\"%s\", nc=%s",
                p_auth->auth_qop, p_auth->auth_cnonce, p_auth->auth_ncstr);
        }

        if (p_auth->auth_algorithm[0] != '\0')
        {
            offset += snprintf(buff+offset, buflen-offset, 
                ", algorithm=%s", p_auth->auth_algorithm);
        }

        offset += snprintf(buff+offset, buflen-offset, "\r\n");
	}
	else if (p_http->auth_mode == 0)	// basic auth
	{
		char auth[128] = {'\0'};
		char basic[256] = {'\0'};
		
		snprintf(auth, sizeof(auth), "%s:%s", p_auth->auth_name, p_auth->auth_pwd);
		
		base64_encode((uint8 *)auth, (int)strlen(auth), basic, sizeof(basic));
		
		offset += snprintf(buff+offset, buflen-offset, "Authorization: Basic %s\r\n", basic);
	}

	return offset;
}

int http_cln_auth_set(HTTPREQ * p_http, const char * user, const char * pass)
{
    if (user)
    {
        strncpy(p_http->auth_info.auth_name, user, sizeof(p_http->auth_info.auth_name)-1);
    }

    if (pass)
    {
        strncpy(p_http->auth_info.auth_pwd, pass, sizeof(p_http->auth_info.auth_pwd)-1);
    }
		
    if (http_get_digest_info(p_http->rx_msg, &p_http->auth_info))
	{
		p_http->auth_mode = 1;  // digest
		strcpy(p_http->auth_info.auth_uri, p_http->url);
	}
	else
	{
		p_http->auth_mode = 0;  // basic
	}
	
    p_http->need_auth = TRUE;

    return p_http->auth_mode;
}

BOOL http_cln_ssl_conn(HTTPREQ * p_http, int timeout)
{
#ifdef HTTPS
    SSL_CTX * ctx = NULL;
	const SSL_METHOD * method = NULL;

	SSLeay_add_ssl_algorithms();  
	SSL_load_error_strings();
	
	method = SSLv23_client_method();  
	ctx = SSL_CTX_new(method);
	if (NULL == ctx)
	{
		log_print(HT_LOG_ERR, "%s, SSL_CTX_new failed!\r\n", __FUNCTION__);
		return FALSE;
	}
    
#if __WINDOWS_OS__
    int tv = timeout;
#else
    struct timeval tv = {timeout / 1000, (timeout % 1000) * 1000};
#endif

    setsockopt(p_http->cfd, SOL_SOCKET, SO_RCVTIMEO, (char*)&tv, sizeof(tv));
    
	p_http->ssl = SSL_new(ctx); 
	if (NULL == p_http->ssl)
	{
	    SSL_CTX_free(ctx);
		log_print(HT_LOG_ERR, "%s, SSL_new failed!\r\n", __FUNCTION__);
		return FALSE;
	}
	
	SSL_set_fd(p_http->ssl, p_http->cfd); 

	if (SSL_connect(p_http->ssl) == -1)
	{
	    SSL_CTX_free(ctx);
		log_print(HT_LOG_ERR, "%s, SSL_connect failed!\r\n", __FUNCTION__);
		return FALSE;
	}

	SSL_CTX_free(ctx);

    p_http->ssl_mutex = sys_os_create_mutex();
    
	return TRUE;
#else
    return FALSE;
#endif
}

BOOL http_cln_rx(HTTPREQ * p_http)
{
	int rlen = 0;
	HTTPMSG * rx_msg;

	if (p_http->rbuf == NULL)
	{
		p_http->rbuf = p_http->rcv_buf;
		p_http->mlen = sizeof(p_http->rcv_buf)-4;
		p_http->rcv_dlen = 0;
		p_http->ctt_len = 0;
		p_http->hdr_len = 0;
	}

#ifdef HTTPS
	if (p_http->https)
	{
	    sys_os_mutex_enter(p_http->ssl_mutex);
	    if (p_http->ssl)
	    {
		    rlen = SSL_read(p_http->ssl, p_http->rbuf+p_http->rcv_dlen, p_http->mlen-p_http->rcv_dlen);
		}
		sys_os_mutex_leave(p_http->ssl_mutex);
	}
	else 
#endif	
    rlen = recv(p_http->cfd, p_http->rbuf+p_http->rcv_dlen, p_http->mlen-p_http->rcv_dlen, 0);

	if (rlen < 0)
	{
		log_print(HT_LOG_INFO, "%s, recv return = %d, dlen[%d], mlen[%d]\r\n", 
		    __FUNCTION__, rlen, p_http->rcv_dlen, p_http->mlen);	
		return FALSE;
	}

	p_http->rcv_dlen += rlen;
	p_http->rbuf[p_http->rcv_dlen] = '\0';    

    if (0 == rlen)
	{
	    if (p_http->rcv_dlen < p_http->ctt_len + p_http->hdr_len && p_http->ctt_len == MAX_CTT_LEN)
	    {
            // without Content-Length filed, when recv finish, fix the ctt length
            p_http->ctt_len = p_http->rcv_dlen - p_http->hdr_len;
        }
        else
        {
            log_print(HT_LOG_INFO, "%s, recv return = %d, dlen[%d], mlen[%d]\r\n", 
                __FUNCTION__, rlen, p_http->rcv_dlen, p_http->mlen);
    		return FALSE;
        }
	}

	if (p_http->rcv_dlen < 16)
	{
		return TRUE;
	}
	
	if (http_is_http_msg(p_http->rbuf) == FALSE)
	{
		return FALSE;
	}
	
	rx_msg = NULL;

	if (p_http->hdr_len == 0)
	{
		int parse_len;
		int http_pkt_len;

		http_pkt_len = http_pkt_find_end(p_http->rbuf);
		if (http_pkt_len == 0) 
		{
			return TRUE;
		}
		p_http->hdr_len = http_pkt_len;

        rx_msg = http_get_msg_buf(http_pkt_len+1);
		if (rx_msg == NULL)
		{
			log_print(HT_LOG_ERR, "%s, get msg buf failed\r\n", __FUNCTION__);
			return FALSE;
		}

		memcpy(rx_msg->msg_buf, p_http->rbuf, http_pkt_len);
		rx_msg->msg_buf[http_pkt_len] = '\0';
		
		log_print(HT_LOG_DBG, "RX from %s << %s\r\n", p_http->host, rx_msg->msg_buf);
		
		parse_len = http_msg_parse_part1(rx_msg->msg_buf, http_pkt_len, rx_msg);
		if (parse_len != http_pkt_len)
		{
			log_print(HT_LOG_ERR, "%s, http_msg_parse_part1=%d, http_pkt_len=%d!!!\r\n", 
			    __FUNCTION__, parse_len, http_pkt_len);

			http_free_msg(rx_msg);
			return FALSE;
		}
		
		p_http->ctt_len = rx_msg->ctt_len;
	}

    if (p_http->ctt_len == 0 && p_http->rcv_dlen > p_http->hdr_len)
    {
        // without Content-Length field
        p_http->ctt_len = MAX_CTT_LEN;
    }
    
	if ((p_http->ctt_len + p_http->hdr_len) > p_http->mlen)
	{
		if (p_http->dyn_recv_buf)
		{
			free(p_http->dyn_recv_buf);
		}

		p_http->dyn_recv_buf = (char *)malloc(p_http->ctt_len + p_http->hdr_len + 1);
		if (NULL == p_http->dyn_recv_buf)
		{
		    http_free_msg(rx_msg);
		    return FALSE;
		}
		
		memcpy(p_http->dyn_recv_buf, p_http->rcv_buf, p_http->rcv_dlen);
		p_http->rbuf = p_http->dyn_recv_buf;
		p_http->mlen = p_http->ctt_len + p_http->hdr_len;

	    http_free_msg(rx_msg);

        // Need more data
		return TRUE;
	}

	if (p_http->rcv_dlen >= (p_http->ctt_len + p_http->hdr_len))
	{
		if (rx_msg == NULL)
		{
			int nlen;
			int parse_len;

			nlen = p_http->ctt_len + p_http->hdr_len;
			
            rx_msg = http_get_msg_buf(nlen+1);
			if (rx_msg == NULL)
			{
			    log_print(HT_LOG_ERR, "%s, get msg buf failed\r\n", __FUNCTION__);
				return FALSE;
			}

			memcpy(rx_msg->msg_buf, p_http->rbuf, p_http->hdr_len);
			rx_msg->msg_buf[p_http->hdr_len] = '\0';
			
			parse_len = http_msg_parse_part1(rx_msg->msg_buf, p_http->hdr_len, rx_msg);
			if (parse_len != p_http->hdr_len)
			{
				log_print(HT_LOG_ERR, "%s, http_msg_parse_part1=%d, sip_pkt_len=%d!!!\r\n", __FUNCTION__, parse_len, p_http->hdr_len);

				http_free_msg(rx_msg);
				return FALSE;
			}				
		}

		if (p_http->ctt_len > 0)
		{
			int parse_len;
			
			memcpy(rx_msg->msg_buf+p_http->hdr_len, p_http->rbuf+p_http->hdr_len, p_http->ctt_len);
			rx_msg->msg_buf[p_http->hdr_len + p_http->ctt_len] = '\0';

			if (ctt_is_string(rx_msg->ctt_type))
			{
				log_print(HT_LOG_DBG, "%s\r\n\r\n", rx_msg->msg_buf+p_http->hdr_len);
			}
			
			parse_len = http_msg_parse_part2(rx_msg->msg_buf+p_http->hdr_len, p_http->ctt_len, rx_msg);
			if (parse_len != p_http->ctt_len)
			{
				log_print(HT_LOG_ERR, "%s, http_msg_parse_part2=%d, sdp_pkt_len=%d!!!\r\n", __FUNCTION__, parse_len, p_http->ctt_len);

				http_free_msg(rx_msg);
				return FALSE;
			}
		}

		p_http->rx_msg = rx_msg;
	}

	if (p_http->rx_msg != rx_msg) 
	{
        http_free_msg(rx_msg);
    }
	
	return TRUE;
}

int http_cln_tx(HTTPREQ * p_http, const char * p_data, int len)
{
    int slen = 0;
    
	if (p_http->cfd <= 0)
	{
		return -1;
    }
    
#ifdef HTTPS
	if (p_http->https)
	{
	    sys_os_mutex_enter(p_http->ssl_mutex);
	    if (p_http->ssl)
	    {
		    slen = SSL_write(p_http->ssl, p_data, len);
		}
		sys_os_mutex_leave(p_http->ssl_mutex);
	}
	else 
#endif	
    slen = send(p_http->cfd, p_data, len, 0);
	
	return slen;
}

BOOL http_cln_rx_timeout(HTTPREQ * p_http, int timeout)
{
	int count = 0;
	int sret;
	BOOL ret = FALSE;
	fd_set fdr;
	struct timeval tv;
	
	while (1)
	{
#ifdef HTTPS
        if (p_http->https && SSL_pending(p_http->ssl) > 0)
    	{
    	    // There is data to read 
    	}
    	else
#endif
        {
    		tv.tv_sec = 1;
    		tv.tv_usec = 0;
    		
    		FD_ZERO(&fdr);
    		FD_SET(p_http->cfd, &fdr);

    		sret = select((int)(p_http->cfd+1), &fdr, NULL, NULL, &tv);
    		if (sret == 0)
    		{
    		    count++;
    		    
    		    if (count >= timeout / 1000)
    		    {
    		        log_print(HT_LOG_WARN, "%s, timeout!!!\r\n", __FUNCTION__);
    		        break;
    		    }
    		    
    			continue;
    		}
    		else if (sret < 0)
    		{
    			log_print(HT_LOG_ERR, "%s, select err[%s], sret[%d]!!!\r\n", 
    			    __FUNCTION__, sys_os_get_socket_error(), sret);
    			break;
    		}
    		else if (!FD_ISSET(p_http->cfd, &fdr))
    		{
    		    continue;
    		}
		}
		
		if (http_cln_rx(p_http) == FALSE)
		{
			break;
		}	
		else if (p_http->rx_msg != NULL)
		{
			ret = TRUE;
			break;
		}	
	}

	return ret;
}

void http_cln_free_req(HTTPREQ * p_http)
{
	if (p_http->cfd > 0)
	{
		closesocket(p_http->cfd);
		p_http->cfd = 0;
	}

#ifdef HTTPS
	if (p_http->https)
	{
	    if (p_http->ssl)
	    {
	        sys_os_mutex_enter(p_http->ssl_mutex);
    		SSL_free(p_http->ssl);
    		p_http->ssl = NULL;
    		sys_os_mutex_leave(p_http->ssl_mutex);
		}

		if (p_http->ssl_mutex)
		{
		    sys_os_destroy_sig_mutex(p_http->ssl_mutex);
		    p_http->ssl_mutex = NULL;
		}
	}
#endif

	if (p_http->dyn_recv_buf)
	{
		free(p_http->dyn_recv_buf);
		p_http->dyn_recv_buf = NULL;
	}	
	
	if (p_http->rx_msg)
	{
		http_free_msg(p_http->rx_msg);
		p_http->rx_msg = NULL;
	}

	p_http->rcv_dlen = 0;
	p_http->hdr_len = 0;
	p_http->ctt_len = 0;
	p_http->rbuf = NULL;
	p_http->mlen = 0;
}






