热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

openssl实现https网站

下面是一个用openssl实现获取https网页内容的demo,整个流程比较简单,主要封装的API如下staticinthttps_init(http

下面是一个用openssl  实现获取https 网页内容的demo,整个流程比较简单,主要封装的API如下

static int https_init(https_context_t *context,const char* url);
static int https_uninit(https_context_t *context);
static int https_read(https_context_t *context,void* buff,int len);
static int https_write(https_context_t *context,const void* buff,int len);
static int https_get_status_code(https_context_t *context);
static int https_read_content(https_context_t *context,char *resp_contet,int max_len);

通信流程:

1、初始化,解析url资源,创建socket 连接,绑定ssl

2、发送http 请求

3、获取请求返回的状态码

4、获取请求返回的数据

5、销毁动态申请的内存资源

我就把整个代码贴在下面


#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include #define HTTP_REQ_LENGTH 512
#define HTTP_RESP_LENGTH 20480typedef struct
{int sock_fd;SSL_CTX *ssl_ct;SSL *ssl;//url 解析出来的信息char *host;char *path;int port;
} https_context_t;static int https_init(https_context_t *context,const char* url);
static int https_uninit(https_context_t *context);
static int https_read(https_context_t *context,void* buff,int len);
static int https_write(https_context_t *context,const void* buff,int len);
static int https_get_status_code(https_context_t *context);
static int https_read_content(https_context_t *context,char *resp_contet,int max_len);// http 请求头信息
static char https_header[] ="GET %s HTTP/1.1\r\n""Host: %s:%d\r\n""Connection: Close\r\n""Accept: */*\r\n""\r\n";static char http_req_content[HTTP_REQ_LENGTH] = {0};
static char https_resp_content[HTTP_RESP_LENGTH+1] = {0};static int create_request_socket(const char* host,const int port)
{int sockfd;struct hostent *server;struct sockaddr_in serv_addr;sockfd &#61; socket(AF_INET, SOCK_STREAM, 0);if (sockfd <0){printf("[http_demo] create_request_socket create socket fail.\n");return -1;}/* lookup the ip address */server &#61; gethostbyname(host);if(server &#61;&#61; NULL){printf("[http_demo] create_request_socket gethostbyname fail.\n");close(sockfd);return -1;}memset(&serv_addr,0,sizeof(serv_addr));serv_addr.sin_family &#61; AF_INET;serv_addr.sin_port &#61; htons(port);memcpy(&serv_addr.sin_addr.s_addr,server->h_addr,server->h_length);if (connect(sockfd,(struct sockaddr *)&serv_addr,sizeof(serv_addr)) <0){printf("[http_demo] create_request_socket connect fail.\n");close(sockfd);return -1;}return sockfd;
}/*** &#64;brief https_parser_url 解析出https 中的域名、端口和路径* &#64;param url 需要解析的url* &#64;param host 解析出来的域名或者ip* &#64;param port 端口&#xff0c;没有时默认返回443* &#64;param path 路径&#xff0c;指的是域名后面的位置* &#64;return*/
static int https_parser_url(const char* url,char **host,int *port,char **path)
{if(url &#61;&#61; NULL || strlen(url) <9 || host &#61;&#61; NULL || path &#61;&#61; NULL){printf("[https_demo] url or host or path is null.\n");return -1;}//判断是不是 https://int i &#61; 0;char https_prefix[] &#61; "https://";for(i&#61;0;i<8;i&#43;&#43;){if(url[i] !&#61; https_prefix[i]){printf("[https_demo] illegal url &#61; %s.\n",url);return -1;}}const char *temp &#61; url&#43;i;while(*temp !&#61; &#39;/&#39;) //next /{if(*temp &#61;&#61; &#39;\0&#39;) //{printf("[https_demo] illegal url &#61; %s.\n",url);return -1;}temp&#43;&#43;;}const char *host_port &#61; url&#43;i;while(*host_port !&#61; &#39;:&#39; && *host_port !&#61; &#39;/&#39;) //找到 :或者 / 结束{host_port &#43;&#43;;}int host_len &#61; host_port-url-i; //减掉https://int path_len &#61; strlen(temp);char *host_temp &#61; (char *)malloc(host_len &#43; 1); //多一个字符串结束标识 \0if(host_temp &#61;&#61; NULL){printf("[https_demo] malloc host fail.\n");return -1;}if(*host_port&#43;&#43; &#61;&#61; &#39;:&#39;) //url 中有端口{*port &#61; 0;while(*host_port !&#61;&#39;/&#39; && *host_port !&#61;&#39;\0&#39;) //十进制字符串转成数字{*port *&#61; 10;*port &#43;&#61; (*host_port - &#39;0&#39;);host_port &#43;&#43;;}}else{*port &#61; 443;}char *path_temp &#61; (char *)malloc(path_len &#43; 1); //多一个字符串结束标识 \0if(path_temp &#61;&#61; NULL){printf("[https_demo] malloc path fail.\n");free(host_temp);return -1;}memcpy(host_temp,url&#43;i,host_len);memcpy(path_temp,temp,path_len);host_temp[host_len] &#61; &#39;\0&#39;;path_temp[path_len] &#61; &#39;\0&#39;;*host &#61; host_temp;*path &#61; path_temp;return 0;
}static int https_init(https_context_t *context,const char* url)
{if(context &#61;&#61; NULL){printf("[https_demo] init https_context_t is null.\n");return -1;}if(https_parser_url(url,&(context->host),&(context->port),&(context->path))){printf("[https_demo] https_parser_url fail.\n");return -1;}context->sock_fd &#61; create_request_socket(context->host,context->port);if(context->sock_fd <0){printf("[https_demo] create_request_socket fail.\n");goto https_init_fail;}context->ssl_ct &#61; SSL_CTX_new(SSLv23_method());if(context->ssl_ct &#61;&#61; NULL){printf("[https_demo] SSL_CTX_new fail.\n");goto https_init_fail;}context->ssl &#61; SSL_new(context->ssl_ct);if(context->ssl &#61;&#61; NULL){printf("[https_demo] SSL_new fail.\n");goto https_init_fail;}if(SSL_set_fd(context->ssl,context->sock_fd)<0){printf("[https_demo] SSL_set_fd fail \n");}if(SSL_connect(context->ssl) &#61;&#61; -1){printf("[https_demo] SSL_connect fail.\n");goto https_init_fail;}return 0;
https_init_fail:https_uninit(context);return -1;
}static int https_read(https_context_t *context,void* buff,int len)
{if(context &#61;&#61; NULL || context->ssl &#61;&#61; NULL){printf("[https_demo] read https_context_t or ssl is null.\n");return -1;}return SSL_read(context->ssl,buff,len);
}static int https_write(https_context_t *context,const void* buff,int len)
{if(context &#61;&#61; NULL || context->ssl &#61;&#61; NULL){printf("[https_demo] write https_context_t or ssl is null.\n");return -1;}return SSL_write(context->ssl,buff,len);
}static int https_get_status_code(https_context_t *context)
{if(context &#61;&#61; NULL || context->ssl &#61;&#61; NULL){printf("[https_demo] get status https_context_t or ssl is null.\n");return -1;}int ret;int flag &#61;0;int recv_len &#61; 0;char res_header[1024] &#61; {0};while(recv_len<1023){ret &#61; SSL_read(context->ssl, res_header&#43;recv_len, 1);if(ret<1) // recv fail{break;}//找到响应头的头部信息, 两个"\r\n"为分割点if((res_header[recv_len]&#61;&#61;&#39;\r&#39;&&(flag&#61;&#61;0||flag&#61;&#61;2))||(res_header[recv_len]&#61;&#61;&#39;\n&#39;&&(flag&#61;&#61;1||flag&#61;&#61;3))){flag&#43;&#43;;}else{flag &#61; 0;}recv_len&#43;&#61;ret;if(flag&#61;&#61;4){break;}}//printf("[http_demo] recv_len&#61;%d res_header &#61; %s.\n",recv_len,res_header);/*获取响应头的信息*/int status_code &#61; -1;char *pos &#61; strstr(res_header, "HTTP/");if(pos){sscanf(pos, "%*s %d", &status_code);//返回状态码}return status_code;
}static int https_read_content(https_context_t *context,char *resp_contet,int max_len)
{if(context &#61;&#61; NULL || context->ssl &#61;&#61; NULL){printf("[https_demo] read content https_context_t or ssl is null.\n");return -1;}int ret ;int recv_size &#61; 0;while(recv_size ssl,resp_contet &#43; recv_size,max_len-recv_size);if(ret <1){break;}recv_size &#43;&#61; ret;}return recv_size;
}static int https_uninit(https_context_t *context)
{if(context &#61;&#61; NULL){printf("[https_demo] uninit https_context_t is null.\n");return -1;}if(context->host !&#61; NULL){free(context->host);context->host &#61; NULL;}if(context->path !&#61; NULL){free(context->path);context->path &#61; NULL;}if(context->ssl !&#61; NULL){SSL_shutdown(context->ssl);//SSl_free(context->ssl);context->ssl &#61; NULL;}if(context->ssl_ct !&#61; NULL){SSL_CTX_free(context->ssl_ct);context->ssl_ct &#61; NULL;}if(context->sock_fd > 0){close(context->sock_fd);context->sock_fd &#61; -1;}return 0;
}int main()
{https_context_t https_ct &#61; {0};int ret &#61; SSL_library_init();printf("[https_demo] SSL_library_init ret &#61; %d.\n",ret);https_init(&https_ct,"https://www.baidu.com/");ret &#61; snprintf(http_req_content,HTTP_REQ_LENGTH,https_header,https_ct.path,https_ct.host,https_ct.port);ret &#61; https_write(&https_ct,http_req_content,ret);printf("[https_demo] https_write ret &#61; %d.\n",ret);if(https_get_status_code(&https_ct) &#61;&#61; 200){ret &#61; https_read_content(&https_ct,https_resp_content,HTTP_RESP_LENGTH);if(ret > 0){https_resp_content[ret] &#61; &#39;\0&#39;; //字符串结束标识printf("[https_demo] https_write https_resp_content &#61; \n %s.\n",https_resp_content);}}https_uninit(&https_ct);return 0;
}

 


推荐阅读
author-avatar
111222
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有