力战者
力战者,天酬之!
#include <string>
#include <stdio.h>
#include <iostream>
#include<fstream>

#include "curl.h"

#ifdef WIN32
#include <corecrt_io.h>
#else
#include "unistd.h"
#include<unistd.h>
#endif
#include "curl_http.h"
#include "md5.h"
#include "OperateFile.h"
using namespace std;


curl_http::curl_http()
: list(NULL)
{
}

curl_http::~curl_http()
{
    if (list)
    {
        curl_slist_free_all(list);
    }
}


void curl_http::add_header(const std::string & header)
{
    list = curl_slist_append(list, header.c_str());
}


static size_t OnWriteData(void* buffer, size_t size, size_t nmemb, void* lpVoid)
{
    std::string* str = dynamic_cast<std::string*>((std::string *)lpVoid);
    if (NULL == str || NULL == buffer)
    {
        return -1;
    }
    char* pData = (char*)buffer;
    str->append(pData, size * nmemb);
    return nmemb;
}


int curl_http::Post(std::string strUrl, std::string strPost, int& statusCode, std::string& strResponse) {
    CURLcode res;
    CURL* curl = curl_easy_init();
    if (NULL == curl)
    {
        return CURLE_FAILED_INIT;
    }
    curl_easy_setopt(curl, CURLOPT_URL, strUrl.c_str());
    if (list)
    {
        curl_easy_setopt(curl, CURLOPT_HTTPHEADER, list);
    }
    curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0L);               //验证SSL证书
    curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0L);               //验证主机名的SSL
    curl_easy_setopt(curl, CURLOPT_POST, 1);                          //发送一个HTTP POST要求
    curl_easy_setopt(curl, CURLOPT_POSTFIELDS, strPost.c_str());      //用这个数据发送一个POST
    curl_easy_setopt(curl, CURLOPT_READFUNCTION, NULL);               //读取数据回调
    curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, OnWriteData);       //写入数据的回调
    curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *)&strResponse);  //数据指针传递给写回调
    curl_easy_setopt(curl, CURLOPT_NOSIGNAL, 1);                      //不安装信号处理程序
    curl_easy_setopt(curl, CURLOPT_TIMEOUT, 3);                       //整个请求超时时间
    curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, 3);                //连接阶段超时时间
    curl_easy_setopt(curl, CURLOPT_USERAGENT, "pc_student");          //用户代理:标头
    res = curl_easy_perform(curl);
    curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &statusCode);
    curl_easy_cleanup(curl);
    return res;
}


static size_t OnWriteFile(void* buffer, size_t size, size_t nmemb, void* lpVoid)
{
    FILE* stream = (FILE*)lpVoid;
    if (nullptr == stream || nullptr == buffer)
    {
        return -1;
    }
    size_t nWrite = fwrite(buffer, size, nmemb, stream);
    return nWrite;
}

int OnProgress(void *ptr, double totalToDownload, double nowDownloaded, double totalToUpLoad, double nowUpLoaded)
{
    int tmp = 0;
    long localLen = *(long*)ptr;
    if ( totalToDownload > 0 )
    {
        tmp = (int)((nowDownloaded + (double)localLen) / (totalToDownload + (double)localLen) * 100);
    }
    printf("下载进度%0d%%\r", tmp);
    return 0;
}

size_t ProgressFunc(double* pFileLen,
                 double t,// 下载时总大小
                 double d, // 已经下载大小
                 double ultotal, // 上传是总大小
                 double ulnow)   // 已经上传大小
{
    if(t == 0) return 0;
    *pFileLen = d;
    return 0;
}


curl_http_downloader::curl_http_downloader(const std::string& name)
: m_file(nullptr)
, m_TargetName(name)
, m_progress(nullptr)
{
}

curl_http_downloader::~curl_http_downloader()
{
}

bool curl_http_downloader::DownloadFileContent(const std::string& url,
    const std::string& Targetfilepath, 
    const std::string& Temfilepath,
    string SizeRange)
{
    CURLcode res;
    if(OpenFile(Temfilepath,m_file) || OpenFile(Targetfilepath,m_ExitFile))
        return false;
    
    CURL* _curl = curl_easy_init();

    if (nullptr == _curl)
    {
        CloseFile(m_file);
        CloseFile(m_ExitFile);
        return false;
    }

    curl_easy_setopt(_curl, CURLOPT_URL, url.c_str());
    curl_easy_setopt(_curl, CURLOPT_WRITEFUNCTION, OnWriteFile);
    curl_easy_setopt(_curl, CURLOPT_WRITEDATA, m_file);
    curl_easy_setopt(_curl, CURLOPT_NOPROGRESS, false);
    curl_easy_setopt(_curl, CURLOPT_PROGRESSFUNCTION, OnProgress);
    curl_easy_setopt(_curl, CURLOPT_NOSIGNAL, 1L);
    curl_easy_setopt(_curl, CURLOPT_LOW_SPEED_LIMIT, 1L);
    curl_easy_setopt(_curl, CURLOPT_LOW_SPEED_TIME, 5L);

    curl_easy_setopt(_curl, CURLOPT_HEADER, 0L);
    curl_easy_setopt(_curl, CURLOPT_NOBODY, 0L);
    curl_easy_setopt(_curl, CURLOPT_FOLLOWLOCATION, 1L);
    //curl_easy_setopt(_curl, CURLOPT_MAX_RECV_SPEED_LARGE, (curl_off_t)1000);

    if (SizeRange == "")
        curl_easy_setopt(_curl, CURLOPT_RESUME_FROM, m_LocalFilelen);
    else
        curl_easy_setopt(_curl, CURLOPT_RANGE, SizeRange.c_str());

    curl_easy_setopt(_curl, CURLOPT_PROGRESSDATA, &m_LocalFilelen);



    res = curl_easy_perform(_curl);                 //完成curl_easy_setopt指定的所有选项,并返回状态
    curl_easy_cleanup(_curl);
    
   
    
    CloseFile(m_file);
    CloseFile(m_ExitFile);

    if (CURLE_OK == res)
        return true;
    else
        return false;
}



int curl_http_downloader::Download(const std::string& url, const std::string& path, progressFunc func,string CurrectMD5)
{
    m_filePath = path;
    
#ifdef WIN32
    m_TargetFileNamepath = m_filePath  + "temp.downloading";
    m_Tempinterfilepath = m_filePath + "temp";
#else
    m_TargetFileNamepath = m_filePath  + "temp.downloading";
    m_Tempinterfilepath = m_filePath +  "temp";
#endif
    
    m_LocalFilelen = GetFileLength(m_TargetFileNamepath); //获取已下载文件大小
    bool CricleFlags = true;                 //CricleFlags为dfalse时,说明下载文件错误,重新下载错误部分
    bool Downloadflags = true;               //Downloadflags为dfalse时,将进行下载与拼接
    string range = "";
    do{
        
       bool result = DownloadFileContent(url, m_TargetFileNamepath, m_Tempinterfilepath, range);
        if (result) {
            std::string fullName = m_filePath + m_TargetName;

            if(Downloadflags)
                MergerFile(m_Tempinterfilepath,m_TargetFileNamepath);
            else
                ToRightMergerFile(m_TargetFileNamepath, m_Tempinterfilepath);
                
            string  m_fileMD5 = MD5::getFileMd5(m_TargetFileNamepath);
                
            int bmoved = 0;
            #ifdef WIN32
            if (_access(m_TargetFileNamepath.c_str(), 0) == 0)
                remove(fullName.c_str());
            #else
            if (access(m_TargetFileNamepath.c_str(), 0) == 0)
                remove(fullName.c_str());
            #endif // WIN 32

            if(CurrectMD5 == m_fileMD5){                                            //MD5校验
                bmoved = rename(m_TargetFileNamepath.c_str(), fullName.c_str());
                remove(m_Tempinterfilepath.c_str());
                CricleFlags = true;
            }
            else{
                ExchangFileName(m_Tempinterfilepath, m_TargetFileNamepath);
                remove(m_Tempinterfilepath.c_str());
                if((Downloadflags = !Downloadflags))
                    range = "";
                else
                    range = "0-" + to_string(m_LocalFilelen-1) ;
                CricleFlags = false;
            }
            if (bmoved) {
                //std::cerr << "move file: " << m_fileNameTmp << " to: " << fullName <<" failed! ";
                return -1;
            }
        }
        else{
            if(GetFileLength(m_Tempinterfilepath)){
                MergerFile(m_Tempinterfilepath,m_TargetFileNamepath);
                remove(m_Tempinterfilepath.c_str());
            }
        }
    }while(!CricleFlags);
    CloseFile(m_file);
    CloseFile(m_ExitFile);
    return 0;
}


int curl_http_downloader::Pause() {
    if (nullptr != m_download_info) {
        m_download_info->status = PAUSED;
    }
    return 0;
}

 

posted on 2019-05-16 21:12  力战者  阅读(284)  评论(0编辑  收藏  举报