C 实现HTTP GET请求MD5 认证

本文介绍了如何使用C语言编写HTTP GET请求,并结合CGI实现MD5身份验证。文章提供了Windows下的编译方法及源码示例。

最新由于某个项目,需要实现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;
}

 

 


 

 

 

 

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值