最新由于某个项目,需要实现http client cgi请求,就尝试用c写出来,顺便记录下。。。第一个博客。。。
修改了下windows下编译。
gcc -o http_send_cgi_msg http_send_cgi_msg.c -lcrypto
以下是源码:
http_send_cgi_msg.c
/*File : http_send_cgi_msg.c
*Auth : Leibo
*Date : 20171018
*Mail : sunhson@163.com
*/
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<openssl/md5.h>
#ifdef WIN32
#include <winsock2.h>
//#include <Ws2tcpip.h>
#pragma comment(lib,"ws2_32.lib")
#pragma warning(disable:4996)
#else
#include<unistd.h>
#include<sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#endif
#define HTTP_METHOD_GET 1
#define HTTP_METHOD_POST 2
#define HTTP_MD5_LEN 16
#define HTTP_MD5_STR_LEN 33 //32+1
#define HTTP_SERVER_IP "10.10.10.114"
#define HTTP_SERVER_PORT 80
#define HTTP_STRING_SIZE 256
#define HTTP_BUFFER_SIZE 10240
#define HTTP_STATUS_OK 200
#define HTTP_STATUS_UNAUTHORIZED 401
#define HTTP_STATUS_ERROR 0
#define HTTP_AUTH_NC "00000001"
#define HTTP_AUTH_CNONCE "8c28955e90665322"
static char http_user[HTTP_STRING_SIZE] = "admin";
static char http_password[HTTP_STRING_SIZE] = "admin";
typedef struct _HTTP_MSG_PARA
{
int method;
char uri[HTTP_STRING_SIZE];
char user[HTTP_STRING_SIZE];
char pwd[HTTP_STRING_SIZE];
char body[HTTP_BUFFER_SIZE];
}HTTP_MSG_PARA;
typedef struct _HTTP_AUTH_PARA
{
char realm[HTTP_STRING_SIZE];
char qop[HTTP_STRING_SIZE];
char nonce[HTTP_STRING_SIZE];
char opaque[HTTP_STRING_SIZE];
}HTTP_AUTH_PARA;
#define HTTP_GET_URL "GET %s HTTP/1.1\r\nHOST: %s:%d\r\nAccept: */*\r\n\r\n"
#define HTTP_GET_AUTH_URL "GET %s HTTP/1.1\r\nHost: %s:%d\r\nAccept: */*\r\n"\
"Authorization: Digest username=\"%s\", realm=\"%s\", nonce=\"%s\", uri=\"%s\", response=\"%s\", opaque=\"%s\", qop=%s, nc=%s, cnonce=\"%s\"\r\n\r\n"
static int http_socket_create(const char *host, int port)
{
struct sockaddr_in server_addr;
int socket_fd = -1;
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(port);
server_addr.sin_addr.s_addr = inet_addr(host);
if((socket_fd = socket(AF_INET, SOCK_STREAM, 0)) == -1)
{
return -1;
}
if(connect(socket_fd, (struct sockaddr *)&server_addr,sizeof(struct sockaddr)) == -1)
{
return -1;
}
return socket_fd;
}
static void http_socket_close(int socket)
{
#ifdef WIN32
closesocket(socket);
#else
close(socket);
#endif
}
int http_check_status(const char*recvbuff)
{
char *p = NULL;
p = (char*)strstr(recvbuff, "HTTP/1.1");
if(!p){
printf("http/1.1 not faind\n");
return HTTP_STATUS_ERROR;
}
if(atoi(p + 9) == 200){
return HTTP_STATUS_OK;
}
if(atoi(p + 9) == 401){
return HTTP_STATUS_UNAUTHORIZED;
}
return HTTP_STATUS_ERROR;
}
int http_get_auth_para(HTTP_AUTH_PARA *apara, char *msg, int msglen)
{
char *p = NULL;
if(msglen > HTTP_BUFFER_SIZE)
return -1;
p = (char*)strstr(msg, "Digest realm=\"");
if(p)
{
sscanf(p + strlen("Digest realm=\""), "%[^\"]", apara->realm);
}
p = (char*)strstr(msg, "qop=\"");
if(p)
{
sscanf(p + strlen("qop=\""), "%[^\"]", apara->qop);
}
p = (char*)strstr(msg, "nonce=\"");
if(p)
{
sscanf(p + strlen("nonce=\""), "%[^\"]", apara->nonce);
}
p = (char*)strstr(msg, "opaque=\"");
if(p)
{
sscanf(p + strlen("opaque=\""), "%[^\"]", apara->opaque);
}
return 0;
}
int http_md5_hex_to_str(unsigned char *str, int len, unsigned char *hexstr)
{
int i = 0;
unsigned char md5[HTTP_MD5_LEN + 1] = {0};
MD5((const unsigned char*)str, len, md5);
md5[HTTP_MD5_LEN] = '\0';
for(i = 0; i < HTTP_MD5_LEN; i++)
{
sprintf((char *)hexstr + i * 2, "%02x", md5[i]);
}
hexstr[HTTP_MD5_STR_LEN - 1] = '\0';
return 0;
}
int http_md5_auth_response(HTTP_MSG_PARA mpara, HTTP_AUTH_PARA apara, char *authResp, int *len)
{
unsigned char md5tmp[HTTP_STRING_SIZE] = {0};
unsigned char md5hexstr_HA1[HTTP_MD5_STR_LEN] = {0};
unsigned char md5hexstr_HA2[HTTP_MD5_STR_LEN] = {0};
unsigned char md5hexstr_HD[HTTP_MD5_STR_LEN] = {0};
//HA1=username:realm:password
sprintf((char *)md5tmp, "%s:%s:%s", http_user, apara.realm, http_password);
http_md5_hex_to_str(md5tmp, strlen((const char*)md5tmp), md5hexstr_HA1);
//HA2=method:uri
memset(md5tmp, 0, HTTP_STRING_SIZE);
if(mpara.method == HTTP_METHOD_GET)
sprintf((char *)md5tmp, "%s:%s", "GET", mpara.uri);
else if(mpara.method == HTTP_METHOD_POST)
sprintf((char *)md5tmp, "%s:%s", "PSOT", mpara.uri);
http_md5_hex_to_str(md5tmp, strlen((const char*)md5tmp), md5hexstr_HA2);
memset(md5tmp, 0, HTTP_STRING_SIZE);
sprintf((char *)md5tmp, "%s:%s:%s:%s:%s:%s", md5hexstr_HA1, apara.nonce, HTTP_AUTH_NC, HTTP_AUTH_CNONCE, apara.qop, md5hexstr_HA2);
http_md5_hex_to_str(md5tmp, strlen((const char*)md5tmp), md5hexstr_HD);
if(strlen((char*)md5hexstr_HD) < HTTP_MD5_STR_LEN)
{
*len = strlen((char*)md5hexstr_HD);
strncpy(authResp, (char*)md5hexstr_HD, *len);
}
return 0;
}
int http_send_first_msg(HTTP_MSG_PARA mpara, char *recvbuff, int *rlen)
{
int len = 0;
int socket_fd = -1;
char buff[HTTP_BUFFER_SIZE] = {0};
socket_fd = http_socket_create(HTTP_SERVER_IP, HTTP_SERVER_PORT);
if(socket_fd < 0)
return -1;
if(mpara.method == HTTP_METHOD_GET)
{
sprintf(buff, HTTP_GET_URL, mpara.uri, HTTP_SERVER_IP, HTTP_SERVER_PORT);
}
else if(mpara.method == HTTP_METHOD_POST)
{
//ToDo:
}
else
return -1;
if(send(socket_fd, buff, strlen(buff)+1, 0) < 0)
return -1;
memset(buff, 0, HTTP_BUFFER_SIZE);
len = recv(socket_fd, buff, HTTP_BUFFER_SIZE, 0);
if(len <= HTTP_BUFFER_SIZE)
strncpy(recvbuff, buff, len);
*rlen = len;
http_socket_close(socket_fd);
return 0;
}
int http_send_auth_msg(HTTP_MSG_PARA mpara, HTTP_AUTH_PARA apara, char *recvbuff, int *rlen)
{
int len = 0;
int socket_fd = -1;
char buff[HTTP_BUFFER_SIZE] = {0};
char md5HDstr[HTTP_MD5_STR_LEN] = {0};
int md5HDlen = 0;
socket_fd = http_socket_create(HTTP_SERVER_IP, HTTP_SERVER_PORT);
if(socket_fd < 0)
return -1;
http_md5_auth_response(mpara, apara, md5HDstr, &md5HDlen);
if(mpara.method == HTTP_METHOD_GET)
{
sprintf(buff, HTTP_GET_AUTH_URL, mpara.uri, HTTP_SERVER_IP, HTTP_SERVER_PORT, http_user, apara.realm, apara.nonce, mpara.uri, md5HDstr, apara.opaque, apara.qop, HTTP_AUTH_NC, HTTP_AUTH_CNONCE);
}
else if(mpara.method == HTTP_METHOD_POST)
{
//ToDo:
}
else
return -1;
if(send(socket_fd, buff, strlen(buff)+1, 0) < 0)
return -1;
memset(buff, 0, HTTP_BUFFER_SIZE);
len = recv(socket_fd, buff, HTTP_BUFFER_SIZE, 0);
if(len < HTTP_BUFFER_SIZE)
strncpy(recvbuff, buff, len);
*rlen = len;
http_socket_close(socket_fd);
return 0;
}
int http_parse_auth_response(char *recvbuff, int len, char *content, int *clen)
{
char *p = NULL;
p = (char*)strstr(recvbuff, "\r\n\r\n");
if(!p)
{
printf("content is NULL\n");
return -1;
}
*clen = strlen(p + 4);
if(*clen < HTTP_BUFFER_SIZE)
strncpy(content, p + 4, *clen);
return 0;
}
int http_encode_uri(char *inuri, char *outuri)
{
int len = 0;
char *p = inuri;
char *q = outuri;
while(*p != '\0')
{
if(len + 3 > HTTP_STRING_SIZE)
return -1;
if(*p == '[')
{
*q++ = '%';
*q++ = '5';
*q++ = 'B';
len += 3;
}
else if(*p == ']')
{
*q++ = '%';
*q++ = '5';
*q++ = 'D';
len += 3;
}
else if(*p == ' ')
{
*q++ = '%';
*q++ = '2';
*q++ = '0';
len += 3;
}
else
{
*q++ = *p;
}
p++;
}
return 0;
}
int http_send_request(int method, char *uri, char *body, char *content, int *clen)
{
char recvBuff[HTTP_BUFFER_SIZE] = {0};
int recvLen = 0;
int contentlen = 0;
char newuri[HTTP_STRING_SIZE]= {0};
HTTP_MSG_PARA sendPara;
memset(&sendPara, 0, sizeof(HTTP_MSG_PARA));
http_encode_uri(uri, newuri);
sendPara.method = method;
strcpy(sendPara.uri, newuri);
strcpy(sendPara.user, http_user);
strcpy(sendPara.pwd, http_password);
strcpy(sendPara.body, body);
if(http_send_first_msg(sendPara, recvBuff, &recvLen) < 0)
return -1;
if(http_check_status(recvBuff) == HTTP_STATUS_UNAUTHORIZED)
{
HTTP_AUTH_PARA authPara;
memset(&authPara, 0, sizeof(HTTP_AUTH_PARA));
http_get_auth_para(&authPara, recvBuff, recvLen);
memset(recvBuff, 0, HTTP_BUFFER_SIZE);
recvLen = 0;
if(http_send_auth_msg(sendPara, authPara, recvBuff, &recvLen) < 0)
return -1;
}
if(http_check_status(recvBuff) != HTTP_STATUS_OK)
{
return -1;
}
http_parse_auth_response(recvBuff, recvLen, content, &contentlen);
*clen = contentlen;
return 0;
}
int main()
{
int len = 0;
char recvBuff[HTTP_BUFFER_SIZE] = {0};
char uri[] = "/cgi-bin/configManager.cgi?action=getConfig";
http_send_request(HTTP_METHOD_GET, uri, "", recvBuff, &len);
printf("len = %d\n", len);
printf("buff [%s]\n", recvBuff);
return 0;
}
本文介绍了如何使用C语言编写HTTP GET请求,并结合CGI实现MD5身份验证。文章提供了Windows下的编译方法及源码示例。
228

被折叠的 条评论
为什么被折叠?



