UtilBox(ub)基础组件 -- EasyCurl 发送http请求(2)

       EasyCurl简单封装了一下libcurl调用,对外的提供抽象化的接口,下面就把源码分享出来,此源码和接口还带进一步完善优化,尤其是一些curl_set_opt()的上层封装。大家可以自己写哈,最后写一个满足自己需求的Curl。

       ubplus_curl.h : EasyCurl的类定义和接口,还有一些宏

/*
* =====================================================================================
 *
 *       Filename:  ubplus_curl.h
 *
 *    Description:  A curl wrapper of libcurl
 *
 *        Created:  08/16/2012 04:55:34 PM
 *       Compiler:  g++ 4.6.1
 *
 *         Author:  Michael LiuXin
 *
 * =====================================================================================
 */
#include <stdlib.h>
#include <stdint.h>
#include <memory.h>
#include <string>
#include <curl/curl.h>

//#define NO_USE_UB_LOG
#include "ub_log.h"

#define	UBPLUS_CURL_OK									0 	/* OK */
#define	UBPLUS_CURL_GLOBAL_INIT_FAILD		1 	/* curl_global_init */
#define	UBPLUS_CURL_EASY_INIT_FAILD			2 	/* curl_easy_init */
#define	UBPLUS_CURL_PERFORM_FAILD				3 	/* curl_easy_perform */
#define	UBPLUS_CURL_SET_OPTION_FAILD		4 	/* curl_easy_setopt */
#define	UBPLUS_CURL_HANDLE_NOT_VAILD 		5 	/* CURL* bad*/
#define	UBPLUS_CURL_URL_NOT_VAILD 			6 	/* url string bad */
#define	UBPLUS_CURL_POST_NOT_VAILD 			7 	/* post data bad */
#define UBPLUS_CURL_USER_BUFFER_NOT_VAILD   8   /* user buffer bad */
#define UBPLUS_CURL_TIMEOUT_NOT_VAILD   	9   /* time bad */

namespace ubplus
{
	typedef size_t (*CURL_CALLBACK)(char*,size_t,size_t,void*);

	extern const char* ERROR_MSG[];

	/**
	 * Wrapper of libcurl
	 */
	class EasyCurl
	{
		public:

			/** 
			 * @brief  : constructor , initialize libcrul
			 */
			EasyCurl();

			/**
			 * @brief  : destroy CURL* 
			 */
			~EasyCurl();

			/** 
			 * @brief  : do curl action
			 *
			 * @return : curl ok or not , get_error() will set
			 */
			int fetch();

			/** 
			 * @brief  : set user's buffer , if we do fetch() then we 
			 * 			 write the content to buffer if user set their
			 * 			 own callback , this buffer will ignore
			 *
			 * @param  : [out] user buffer 
			 * 			 [in] buffer length  
			 *
			 * @return : if buffer is invaild , get_error() will set
			 */
			int set_user_buffer(char** buf,size_t len);

			/** 
			 * @brief  : give curl a callback which is called
			 * 			 when fetched data is ready to copy
			 *
			 * @param  : function pointer
			 */
			int set_curl_callback(CURL_CALLBACK);

			/** 
			 * @brief  : pass to callback lastest param
			 *
			 * @param  : function pointer
			 */
			int set_curl_callback_context(void*);

			/** 
			 * @brief  : curl_set_opt(CURLOPT_URL)
			 *
			 * @param  : [in] url , url string 
			 *
			 * @return : if CURL* not vaild , get_error() will set
			 */
			int set_url(std::string url);

			/** 
			 * @brief  : curl_set_opt(CURLOPT_TIMEOUT)
			 *
			 * @param  : [in] timeout , time in seconds 
			 *
			 * @return : if CURL* not vaild , get_error() will set
			 */
			int set_timeout(unsigned long time);

			/** 
			 * @brief  : enable post method and set post data
			 *
			 * @param  : [in] post , post data
			 *
			 * @return : if CURL* not vaild , get_error() will set
			 */
			int set_post_data(void* post);


			/** 
			 * @brief  : test the curl is good to using
			 *
			 * @return : true , would be used
			 */
			bool is_good() {return this->is_good_;}

			uint8_t get_error(){return this->error_;}

			const char* get_error_msg(){return ERROR_MSG[this->error_];}
			
			bool __global_init();

			static size_t __data_callback(char*,size_t,size_t,void*);

			static size_t total_size(){return total_size_;}

		protected :

			static bool global_init_;

			/* user buffer */
			typedef struct __curl_buffer {
				__curl_buffer(){mem=NULL;offset=0;max=0;}
				char* 	mem;
				size_t 	offset;
				size_t 	max;
			}curl_buffer;

			static curl_buffer user_buffer;

			static size_t total_size_;
			
		private :
			CURL* curl_;
			uint8_t error_;
			bool is_good_;
			
	}; 	// end of class 



} 	// end of namespace

        ubplus_curl.cc :  实现,用到了ub_log.h日志组件

/*
 * =====================================================================================
 *
 *       Filename:  ubplus_curl.cc
 *
 *    Description:  A curl wrapper of libcurl
 *
 *        Created:  08/16/2012 04:55:34 PM
 *       Compiler:  g++ 4.6.1
 *
 *         Author:  Michael LiuXin
 *
 * =====================================================================================
 */
#include "ubplus_curl.h"

#define CURL_OK 0

namespace ubplus
{
	#define CURL_GLOBAL_INIT_ONCE __global_init();

	const char* ERROR_MSG[] = {
		"EasyCurl OK",
		"Global Init Failed",
		"Easy Init Failed",
		"Easy Perform Failed",
		"Easy SetOption Failed",
		"Curl Handle Not Vaild",
		"Curl URL Not Vaild",
		"Curl PostData Not Vaild",
		"Curl User Buffer Not Vaild",
		"Curl TimeOut Not Vaild",

		"Unkown Error"
	};

	// ***********************************************************
 	size_t EasyCurl::__data_callback(char* content,size_t size,size_t n,void* null)
	{
		UB_LOG_DEBUG("[ok=curl] Default callback invoke");
		// copy to buffer(this is from user) and ensure space is enough
		if (NULL != EasyCurl::user_buffer.mem) {

			size_t full = n*size;

			// we have no space
			if (EasyCurl::user_buffer.offset >= EasyCurl::user_buffer.max) {
				UB_LOG_TRACE("[ok=curl] User buffer has no space , ignore ");
				return full;
			}

			// as write enough as we can
			size_t to_write = (EasyCurl::user_buffer.offset+n*size<EasyCurl::user_buffer.max
					? n*size : (EasyCurl::user_buffer.max-EasyCurl::user_buffer.offset));

			memcpy(EasyCurl::user_buffer.mem+EasyCurl::user_buffer.offset,content,to_write);
			UB_LOG_DEBUG("[ok=memory] Copy memory to user buffer");
			EasyCurl::user_buffer.offset += to_write;
			EasyCurl::total_size_ += to_write;
		} 

		return n*size;

	}

	// ***********************************************************
	bool EasyCurl::__global_init()
	{
		if (!EasyCurl::global_init_) {
			// call global init only one time
			CURLcode code = curl_global_init(CURL_GLOBAL_ALL);
			if (CURL_OK != code) {
				this->is_good_ = false;
				this->error_ = UBPLUS_CURL_GLOBAL_INIT_FAILD;
				UB_LOG_FATAL("[err=curl] Curl global init error[%s]",curl_easy_strerror(code));
				return false;
			} else {  	
				UB_LOG_TRACE("[ok=curl] Curl global init");
				EasyCurl::global_init_ = true;
				return true;
			}
		} else
			return true;

	}

	// ***********************************************************
	EasyCurl::EasyCurl()
	{
		CURL_GLOBAL_INIT_ONCE

		// curl initial
		this->curl_ = curl_easy_init();
		if (!this->curl_) {
			this->error_ = UBPLUS_CURL_EASY_INIT_FAILD;
			this->is_good_ = false;
			UB_LOG_WARNNING("[warn=curl] Curl easy init failed");
			return;
		} else {
			// set our default write function
			if (CURL_OK != curl_easy_setopt(this->curl_,CURLOPT_WRITEFUNCTION,EasyCurl::__data_callback)) {
				this->error_ = UBPLUS_CURL_SET_OPTION_FAILD;
				this->is_good_ = false;
			} else {
				this->error_ = UBPLUS_CURL_OK;
				this->is_good_ = true;
			}
		}
			
	}
	
	// ***********************************************************
	EasyCurl::~EasyCurl()
	{
		if (this->curl_) {
			UB_LOG_DEBUG("[ok=curl] Curl cleanup ok");
			curl_easy_cleanup(this->curl_);
		}
	}

	// ***********************************************************
	int EasyCurl::set_curl_callback(CURL_CALLBACK func)
	{
		if (!this->curl_ || !this->is_good_) 
			return this->error_ = UBPLUS_CURL_HANDLE_NOT_VAILD;
						
		if (CURL_OK == curl_easy_setopt(this->curl_,CURLOPT_WRITEFUNCTION,func))
			return UBPLUS_CURL_OK;
		else {
			UB_LOG_WARNNING("[warn=curl] set option[call_back] failed");
			this->error_ = UBPLUS_CURL_SET_OPTION_FAILD;
			return UBPLUS_CURL_SET_OPTION_FAILD;	
		}
	}

	// ***********************************************************
	int EasyCurl::set_curl_callback_context(void* user_context)
	{
		if (!this->curl_ || !this->is_good_) 
			return this->error_ = UBPLUS_CURL_HANDLE_NOT_VAILD;
						
		if (CURL_OK == curl_easy_setopt(this->curl_,CURLOPT_WRITEDATA,user_context))
			return UBPLUS_CURL_OK;
		else {
			UB_LOG_WARNNING("[warn=curl] set option[call_back_context] failed");
			this->error_ = UBPLUS_CURL_SET_OPTION_FAILD;
			return UBPLUS_CURL_SET_OPTION_FAILD;	
		}
	}
	
	// ***********************************************************
	int EasyCurl::set_user_buffer(char** user,size_t len) 
	{
		if (NULL == user || NULL == *user || 0 == len) {
			this->is_good_ = false;
			return this->error_ = UBPLUS_CURL_USER_BUFFER_NOT_VAILD;
		}

		EasyCurl::user_buffer.mem = *user;
		memset(EasyCurl::user_buffer.mem,0,len);
		EasyCurl::user_buffer.offset = 0;
		EasyCurl::user_buffer.max = len;
		UB_LOG_DEBUG("[ok=curl] User Buffer set");

		return UBPLUS_CURL_OK;
	}

	// ***********************************************************
	int EasyCurl::fetch() 
	{
		if (!this->curl_ || !this->is_good_) 
			return this->error_ = UBPLUS_CURL_HANDLE_NOT_VAILD;
		
		// actual perform curl
		CURLcode code = curl_easy_perform(this->curl_);
		// don't forget to clear user buffer
		EasyCurl::user_buffer.offset = 0;
		if (CURL_OK == code) {
			return UBPLUS_CURL_OK;
		} else {
			UB_LOG_WARNNING("[warn=curl] curl perform error[%s]",curl_easy_strerror(code));
			this->error_ = UBPLUS_CURL_PERFORM_FAILD;
			return UBPLUS_CURL_PERFORM_FAILD;
		}
	}

	// ***********************************************************
	int EasyCurl::set_timeout(unsigned long time) 
	{
		if (!this->curl_ || !this->is_good_) 
			return this->error_ = UBPLUS_CURL_HANDLE_NOT_VAILD;

		if (0 == time)
			return this->error_ = UBPLUS_CURL_TIMEOUT_NOT_VAILD;
						
		if (CURL_OK == curl_easy_setopt(this->curl_,CURLOPT_TIMEOUT,time))
			return UBPLUS_CURL_OK;
		else {
			UB_LOG_WARNNING("[warn=curl] set option[timeout] failed");
			this->error_ = UBPLUS_CURL_SET_OPTION_FAILD;
			return UBPLUS_CURL_SET_OPTION_FAILD;	
		}

	}

	// ***********************************************************
	int EasyCurl::set_url(std::string url) 
	{
		if (!this->curl_ || !this->is_good_) 
			return this->error_ = UBPLUS_CURL_HANDLE_NOT_VAILD;

		if (url.length()<5)
			return this->error_ = UBPLUS_CURL_URL_NOT_VAILD;
						
		if (CURL_OK == curl_easy_setopt(this->curl_,CURLOPT_URL,url.c_str()))
			return UBPLUS_CURL_OK;
		else {
			UB_LOG_WARNNING("[warn=curl] set option[url] failed");
			this->error_ = UBPLUS_CURL_URL_NOT_VAILD;
			return UBPLUS_CURL_URL_NOT_VAILD;	
		}
	}

	// ***********************************************************
	int EasyCurl::set_post_data(void* post_data) 
	{
		if (!this->curl_ || !this->is_good_) 
			return this->error_ = UBPLUS_CURL_HANDLE_NOT_VAILD;

		if (NULL == post_data)
			return this->error_ = UBPLUS_CURL_POST_NOT_VAILD;
						
		if (CURL_OK == curl_easy_setopt(this->curl_,CURLOPT_POSTFIELDS,post_data))
			return UBPLUS_CURL_OK;
		else {
			UB_LOG_WARNNING("[warn=curl] set option[post] failed");
			this->error_ = UBPLUS_CURL_POST_NOT_VAILD;
			return UBPLUS_CURL_POST_NOT_VAILD;	
		}
	}

	size_t EasyCurl::total_size_ = 0;
	bool EasyCurl::global_init_ = false;
	EasyCurl::curl_buffer EasyCurl::user_buffer;

} 	// end of namespace

相关推荐