(chttp.c) simple http support, very ugly yet

完成了基本的下载支持,代码还比较简陋。
/*
 * @brief simple http support, very ugly yet
 * @author rui.sun, smallrui@126.com
 * @date 2012-5-30
 * @version 0.1 original version
 * @copyright blog.csdn.net/maikforever
 */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <errno.h>
#include <limits.h>
#include <ctype.h>
#include <assert.h>


#ifdef WIN32
#include <WinSock2.h>
#pragma comment(lib, "ws2_32.lib")
#pragma warning(disable: 4996)
#else
#include <sys/socket.h>
#include <unistd.h>
#include <netinet/in.h>
#include <netdb.h>
#include <arpa/inet.h>
#endif


int get_host(char * src, char * web, char * file, int * port)
{
	char * pa;
	char * pb;


	assert(src != NULL);
	memset(web, 0, sizeof(web));
	memset(file, 0, sizeof(file));
	memset(port, 0, sizeof(port));


	pa = src;
	if (!strncmp(pa, "http://", strlen("http://")))
		pa = src+strlen("http://");
	else if (!strncmp(pa, "https://", strlen("https://")))
		pa = src+strlen("https://");
	pb = strchr(pa, '/');
	if (pb)
	{
		memcpy(web, pa, strlen(pa) - strlen(pb));
		if (pb+1)
		{
			memcpy(file, pb + 1, strlen(pb) - 1);
			file[strlen(pb) - 1] = 0;
		}
	}
	else
	{
		memcpy(web, pa, strlen(pa));
	}


	if (pb) web[strlen(pa) - strlen(pb)] = 0;
	else web[strlen(pa)] = 0;
	pa = strchr(web, ':');
	if (pa) *port = atoi(pa + 1);
	else *port = 80;


	return web != NULL && file != NULL && port != NULL;
}


void set_socket_timeout(int sockfd, int time_sec)
{
#ifdef WIN32
	int timeout = time_sec * 1000;
	setsockopt(sockfd, SOL_SOCKET, SO_SNDTIMEO, (char *)&timeout, sizeof(int));
	setsockopt(sockfd, SOL_SOCKET, SO_RCVTIMEO, (char *)&timeout, sizeof(int));
#else
	struct timeval timeout = {time_sec, 0};
	// timeout.tv_sec = time_sec;
	// timeout.tv_usec = 0;
	setsockopt(socket,SOL_SOCKET,SO_SNDTIMEO,(char *)&timeout,sizeof(struct timeval));
	setsockopt(socket,SOL_SOCKET,SO_RCVTIMEO,(char *)&timeout,sizeof(struct timeval));
#endif
}


#define CHECK_ABORT(abort)	\
	if (abort) \
	{ \
		ret_code = -5; \
		goto exit; \
	}


/*
 * return ret_code
 *      0, no error
 *     -1, cannot connect to host server
 *     -2, create file error
 *     -3, network time out&error
 *     -4, syntax error
 *     -5, abort
 */
int chttp_get(const char * url, const char * localfile, const char * user_agent, int timeout_sec, int * abort, int * status_code, char * redicturl, int * dlbytes)
{
	int sockfd = 0;
	struct sockaddr_in server_addr;
	struct hostent *host;
	char * req_url = NULL;


	char header_buffer[1024];
	char host_addr[256];
	char host_file[1024];
	int portnumber;


	FILE * fp = NULL;
	int ret_code = 0;


	int bytessend = 0;
	int totalsend = 0;
	int nb_tmpbytes = 0;
	int nb_recvbytes = 0;
	char recvbyte;


	char tmpbytes[256];
	int tmpret = 0;


	char * loc_begin = NULL;
	char * loc_tail = NULL;


	char fio_buffer[4096];


#ifdef WIN32
	static int wsainit = 0;
	if (!wsainit)
	{
		WSADATA wsadata;
		WSAStartup(MAKEWORD(1, 1), &wsadata);
		wsainit = 1;
	}
#endif


	assert(url != NULL);
	req_url = strdup(url);


	if (!get_host(req_url, host_addr, host_file, &portnumber))
	{
		ret_code = -1;
		goto exit;
	}


	CHECK_ABORT(*abort);


	if ((host = gethostbyname(host_addr)) == NULL)
	{
		ret_code = -1;
		goto exit;
	}


	CHECK_ABORT(*abort);


	if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1)
	{
		ret_code = -1;
		goto exit;
	}


	memset(&server_addr, 0, sizeof(server_addr));
	server_addr.sin_family=AF_INET;
	server_addr.sin_port=htons(portnumber);
	server_addr.sin_addr=*((struct in_addr *)host->h_addr);


	set_socket_timeout(sockfd, timeout_sec);


	if (connect(sockfd, (struct sockaddr *)(&server_addr), sizeof(struct sockaddr)) == -1)
	{
		ret_code = -1;
		goto exit;
	}


	sprintf (header_buffer, 
		"GET /%s HTTP/1.1\r\n"
		"User-Agent: Android AppleCoreMedia Lavf\r\n"
		"Host: %s\r\n"
		"\r\n", 
		host_file, host_addr);


	CHECK_ABORT(*abort);


	// send request
	bytessend = 0;totalsend = 0;
	nb_tmpbytes=strlen(header_buffer);
	while (totalsend < nb_tmpbytes)
	{
		bytessend = send(sockfd, header_buffer + totalsend, nb_tmpbytes - totalsend, 0);
		if (bytessend==-1)
		{
			ret_code = -1;
			goto exit;
		}
		totalsend += bytessend;


		CHECK_ABORT(*abort);
	}


	nb_recvbytes = 0;
	nb_tmpbytes = 0;
	tmpret = 0;
	memset(header_buffer, 0, sizeof(header_buffer));


	CHECK_ABORT(*abort);


	while((nb_tmpbytes = recv(sockfd, &recvbyte, sizeof(char), 0)) > 0)
	{
		if (nb_tmpbytes != sizeof(char)) break;


		memcpy(header_buffer + nb_recvbytes, &recvbyte, sizeof(char));
		if (strstr(header_buffer, "\r\n\r\n") != NULL)
		{
			tmpret = 1;
			break;
		}


		CHECK_ABORT(*abort);
		nb_recvbytes++;
	}


	if (!tmpret)
	{
		ret_code = -3;
		goto exit;
	}


	memset(tmpbytes, 0, sizeof(tmpbytes));
	sscanf(header_buffer, "HTTP/1.1 %[0-9] *", tmpbytes);
	tmpret = atoi(tmpbytes);
	*status_code = tmpret;
	if (tmpret == 200)
	{
		// downloading task now
		fp = fopen(localfile, "wb");
		if (fp == NULL)
		{
			ret_code = -2;
			goto exit;
		}


		*dlbytes = 0;
		for (;;)
		{
			nb_tmpbytes = recv(sockfd, fio_buffer, sizeof(fio_buffer), 0);
			if (nb_tmpbytes == 0)
			{
				// download is finished.
				ret_code = 0;
				break;
			}


			if (nb_tmpbytes == -1)
			{
				ret_code = -3;
				goto exit;
			}


			fwrite(fio_buffer, 1, nb_tmpbytes, fp);
			*dlbytes += nb_tmpbytes;
			CHECK_ABORT(*abort);


			printf("write bytes %d.\n", nb_tmpbytes);
		}
	}
	else if (tmpret == 301 || tmpret == 302)
	{
		loc_begin = strstr(header_buffer, "Location: ");
		if (loc_begin == NULL)
		{
			ret_code = -4;
			goto exit;
		}


		loc_tail = strstr(loc_begin, "\r\n");
		if (loc_tail == NULL)
		{
			ret_code = -4;
			goto exit;
		}


		memcpy(redicturl, loc_begin + strlen("Location: "), loc_tail - loc_begin - strlen("Location: "));
		redicturl[loc_tail - loc_begin - strlen("Location: ")] = 0;
	}
	else
	{
		ret_code = -3;
		goto exit;
	}


	ret_code = 0;


exit:
	free(req_url);


	if (sockfd != 0)
	{
#ifdef WIN32
		closesocket(sockfd);
#else
		close(sockfd);
#endif
	}


	if (fp != NULL)
	{
		fclose(fp);
	}


	return ret_code;
}


#ifdef TEST_CHTTP
int main(int argc, char * argv[])
{
	const char * url = "http://61.135.183.46/ipad?file=/195/119/xWcw8lNpF7u4XnHPzrGC06.mp4&start=0&end=10";
	const char * localfile = "d:/save_test.ts";
	const char * user_agent = "android";
	int timeout_sec = 2;
	int status_code = 0;
	char redicturl[256];
	int dlbytes;
	int ret_code = 0;
	bool abort;


	// will redirect to 301
	ret_code = chttp_get(url, localfile, user_agent, timeout_sec, &abort, &status_code, redicturl, &dlbytes);
	printf("ret_code = %d.\n", ret_code);


	if (ret_code == 0 && status_code == 301)
	{
		chttp_get(redicturl, localfile, user_agent, timeout_sec, &abort, &status_code, redicturl, &dlbytes);
	}


	return 0;
}
#endif
/*
 * @brief simple http support, very ugly yet
 * @author rui.sun, smallrui@126.com
 * @date 2012-5-30
 * @version 0.1 original version
 * @copyright blog.csdn.net/maikforever
 */
#ifndef CHTTP_H
#define CHTTP_H

/*
 * return ret_code
 *      0, no error
 *     -1, cannot connect to host server
 *     -2, create file error
 *     -3, network time out&error
 *     -4, syntax error
 *     -5, abort
 */
int chttp_get(const char * url, const char * localfile, const char * user_agent, int timeout_sec, int * abort, int * status_code, char * redicturl, int * dlbytes);

#endif



 
 
 
 
 
 
 
 
 
 

                
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值