개발자_이훈규
천천히, 빠르게. 개발자의 Repository
개발자_이훈규
전체 방문자
오늘
어제
  • 분류 전체보기 (473)
    • 티스토리 (4)
    • 개발자 뉴스 (2)
    • 소프트웨어 (203)
      • C (7)
      • c++ (25)
      • Objective-C (3)
      • Do it! 반응형 웹디자인 (4)
      • openGL (8)
      • Java (24)
      • Jni (3)
      • Android (9)
      • Wordpress (2)
      • 버그 만난 후 느낀점 (2)
      • Git (3)
      • node js (2)
      • window tablet (1)
      • HTML (3)
      • javascript (3)
      • perl (1)
      • AngularJS (0)
      • JSON (0)
      • Docker (3)
      • python (5)
      • jQuery (1)
      • MFC (4)
      • cocos studio (6)
      • Golang (1)
      • SQLite3 (0)
      • Spring Boot (8)
      • thymeleaf (0)
      • Django (0)
      • iOS (3)
      • skia (0)
      • VBA (0)
      • PHP (2)
      • Oracle (1)
      • JSP (0)
      • R (0)
    • TCP IP (2)
    • 금융 (0)
      • 금융 Study (0)
      • 금융 Archive (0)
      • 금융 Article (0)
    • 개인 프로젝트 (7)
      • gif 홈페이지 만들기 (0)
      • study app만들기 (0)
      • 크롤러 만들기 (1)
      • 카툰 홈페이지 만들기 (1)
      • 외주 홈페이지 만들기 (3)
      • 웹 홈페이지 만들기 (0)
      • 미디어 서버 만들기 (0)
      • 소개팅 어플 만들기 (0)
      • 인스타그램 풀스택 클론 코딩(인강 노트) (0)
      • 주식 모의거래 만들기 (1)
    • html php mysql (0)
    • node.Js (2)
    • 일상 (2)
    • 빈공간 uml 공부 (0)
    • Ubuntu(linux) (12)
    • 맥OS (10)
      • android 설치하기 (2)
    • Programming quizzes (0)
    • IoT (구 유비쿼터스) (16)
      • 라즈베리 파이 (11)
      • 아두이노 (5)
    • 하드웨어 (5)
      • 아수스 비보탭 노트8 asus vivotap no.. (2)
      • 크레마 카르타 (3)
    • 분석할 문장, 구문, 코드 (0)
    • 키보드 (1)
      • 해피해킹 (1)
    • 코드 라이언 (0)
    • 전자기기 (4)
    • Ted (0)
    • NAS (0)
    • 알고리즘 (0)
    • 연합인포맥스 (0)
    • 이벤트 응모함 (4)

블로그 메뉴

  • 홈
  • 태그
  • 미디어로그
  • 위치로그
  • 방명록

공지사항

인기 글

태그

  • Java
  • install
  • 코드
  • Python
  • ubuntu
  • GIT
  • 개발
  • 예제
  • 우분투
  • C++
  • Example
  • 에러
  • 라즈베리 파이
  • CODE
  • 소스
  • error
  • C
  • 설명
  • 방법
  • 설치

최근 댓글

최근 글

티스토리

hELLO · Designed By 정상우.
개발자_이훈규

천천히, 빠르게. 개발자의 Repository

소프트웨어

[curl] curl_easy_getinfo (2)

2014. 1. 21. 10:17


환경 : ubuntu 12.04 LTS

이번 포스트에서 얻는것, curl_easy_getinfo의 간단한 이해와 url이 잘못되었을 경우에 생성된 파일 처리 방법


이 검색의 이유는 잘못된 URL을 입력해도 파일이 생성되는 것일 방지하기 위해서 getinfo로 시작해서 remove로 끝나는 과정을 적인 것입니다.


시작합니다~~ ^^

dev kyu



curl_easy_getinfo를 사용해서 작성한 것, 코드


curl_easy_getinfo로 동작하기 이전에 상태를 확인하려 했는데 아래의 블로그를 들어가보니 curl을 동작 시킨 이후에 확인할 수 있다. 음.. 파일 열기 전에 확인하고 싶은데...


(아래 블로그에서 갖고온 코드와 주소)

#include <curl/curl.h>


int curl_header_flag = 0;

char *last_use_url;

char *cpy_last_url;


cpy_last_url = (char *)malloc(1000);

memset(cpy_last_url , 0x00, 1000);


CURL *curl_handle;

struct MemoryStruct chunk;

chunk.memory=NULL;

chunk.size = 0;


curl_global_init(CURL_GLOBAL_ALL);

curl_handle = curl_easy_init();

curl_easy_setopt(curl_handle, CURLOPT_TIMEOUT, 10);

curl_easy_setopt(curl_handle, CURLOPT_URL, addr);

curl_easy_setopt(curl_handle, CURLOPT_WRITEFUNCTION, WriteMemoryCallback);

curl_easy_setopt(curl_handle, CURLOPT_HEADER , WriteMemoryCallback);

curl_easy_setopt(curl_handle, CURLOPT_WRITEDATA, (void *)&chunk);

curl_easy_setopt(curl_handle, CURLOPT_USERAGENT, "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1)");

curl_easy_setopt(curl_handle, CURLOPT_FOLLOWLOCATION, 1);


curl_easy_perform(curl_handle);

curl_easy_getinfo(curl_handle, CURLINFO_RESPONSE_CODE, &curl_header_flag);

curl_easy_getinfo(curl_handle, CURLINFO_EFFECTIVE_URL, &last_use_url);

strcpy(cpy_last_url, last_use_url);


curl_easy_cleanup(curl_handle);


fprintf(stderr, "[Report] CURL Header status [%d]\n", curl_header_flag);

fprintf(stderr, "[Report] CURL Last url [%s]\n", cpy_last_url);

[출처] curl_easy_getinfo() 사용|작성자 조르프

 


http://blog.naver.com/handukgyu?Redirect=Log&logNo=100124397913


-----------------------------------------------------------------------------------------------------------------------------------------------------


그냥 이건 참고용.. 코드 쓰다보면 그냥 이렇겠구나~ 한거를 어떤 분이 한글로 정리해주신 것.

curl 라이브러리 사용하기


curl_blogal_init() : 라이브러리 초기화

curl_easy_init() : context 생성

curl_easy_setopt() : 설정

curl_easy_perform() : 페이지 요청 및 콜백 함수들 대기

curl_easy_getInfo() : 페이지의 각종 요소 값들 받기 (해더, 타입, 크기 등등등)

curl_easy_strerror() : 에러 발생시 무슨 에러?

curl_easy_cleanup() : context 삭제

curl_global_cleanup() : 라이브러리 삭제


[출처] Curl|작성자 개구리


( http://manhdh.blog.me/120146975838 )


------------------------------------------------------------------------------------------------------------------------------------------------------


여기서 보면 curl_easy_getinfo를 사용하는 것을 볼 수 있다.


#include <curl/curl.h>

#include <curl/easy.h>

 

int GetConfigFile ( void )

{

const char url[1024] ;

CURL* ctx ;

double statDouble ;

long statLong ;

char* statString = NULL ;

FILE *tmp ;

int rc ;

 

//요청할 url을 저장

strcpy (url , http://127.0.0.1/Config/);

 

//응답올 config파일 저장위치 저장

tmp = fopen("/ugw/UpgradeFile/Config", "w");

if (tmp = NULL) {

   printf(" ERROR .... open file\n");

   return -1;

}

 

//libcurl 초기화

curl_global_init( CURL_GLOBAL_ALL );

 

//context 객체의 생성.

ctx = curl_easy_init();

if( ctx == NULL ) {

   printf(" Unable ... Initialize cURL \n");

   return -1;

}

 

//url이 URL정보임을 알려줌

curl_easy_setopt( ctx, CURLOPT_URL, url );

curl_easy_setopt( ctx, CURLOPT_NOPROGRESS, bTRUE ) ;

curl_easy_setopt( ctx, CURLOPT_WRITEDATA, tmp );

 

const CURLcode code = curl_easy_perform( ctx );

if ( code == CURLE_OK ) {

// HTTP 응답코드를 얻어온다.

if( CURLE_OK == curl_easy_getinfo( ctx , CURLINFO_HTTP_CODE , &statLong ) ){
         PrnMsg( LOG_TEST, "Response code : %ld\n", statLong );
}
// Content-Type 를 얻어온다.
if( CURLE_OK == curl_easy_getinfo( ctx , CURLINFO_CONTENT_TYPE , &statString ) ){
        PrnMsg( LOG_TEST, "Content type: %s\n", statString );
}
// 다운로드한 문서의 크기를 얻어온다.
if( CURLE_OK == curl_easy_getinfo( ctx , CURLINFO_SIZE_DOWNLOAD , &statDouble ) ){
        PrnMsg( LOG_TEST, "Download size (%ld bytes)\n ", statDouble );
}

}

 

fclose(tmp);

curl_easy_cleanup(ctx);

 

return 0;

} 


그런데 이 코드들도 파일을 열기 전, 그러니깐 콜백함수의 FILE을 open하기 전에 확인하는 건 없다... 아예 없는 건가?

아예 없다면 콜백 함수 내에서 확인을 하여서 생성한 파일을 삭제 하던지 취소하던지 해야하는데.. 흠...


------------------------------------------------------------------------------------------------------------------------------------------------------


아래 코드도 주석이 잘되어 있어서 보기 좋다. 아래 코드에서 볼 부분은 html_context_data를 따라다니면서 구경하면 될듯. 계속 보다보니깐 에러 코드를 처리하는 부분이 있는데 내 소스에 한번 적용해봐야 겠다. 에러가 뜨면 그냥 종료하면서 기존 name으로 생성한 파일을 제거하는 작업을 추가하던지 해야지..


using namespace std;

#define HTTP_ONLY
extern "C" {
#include "../curl-7.20.1/curl-7.20.1/include/curl/curl.h"
}
#include<cstdio>
#include<iostream>
#include<string>
#include<sstream>

char *print_cookie(CURL *curl)
{
        char *ret = (char*)malloc(1000);
        struct curl_slist *cookie_list, *t = NULL;
        char *p = NULL, *p1 = NULL, *ptr = ret;

        memset(ret, 0, 1000);
        curl_easy_getinfo(curl, CURLINFO_COOKIELIST, &cookie_list);
        t = cookie_list;
        if (!t) {
                free(ret);
                ret = NULL;
        }
        while (t) {
                printf("%s\n", t->data);
                p = strrchr(t->data, '\t');
                *p = '\0';
                p++;
                p1 = strrchr(t->data, '\t');
                p1++;
                strcpy(ptr, p1);
                strcat(ptr, "=");
                strcat(ptr, p);
                strcat(ptr, "; ");
                ptr += strlen(ptr);
                t = t->next;
        }
        curl_slist_free_all(cookie_list);
        return ret;
}


struct html_context_data
{
        char*   data;   // 버퍼
        size_t  size;   // 사이즈
};


size_t callback_write_memory(void *ptr, size_t size, size_t nmemb, void *stream)
{
        size_t realsize = size * nmemb;
        html_context_data *mem = (html_context_data *)stream;

        mem->data = (char*)realloc(mem->data, mem->size + realsize + 1);
        if (mem->data) {
                memcpy(&(mem->data[mem->size]), ptr, realsize);
                mem->size += realsize;
                mem->data[mem->size] = '\0';
        }

        return realsize;
}

static void free_html_context_data(html_context_data *p)
{
        p ? (free(p->data), p->data = NULL, p->size = 0) : 1;
}

void get_post_data(std::ostringstream& postBuf, const char** pp)
{
        while( NULL != *pp )
        {
                // curl_escape( {string} , 0 ): replace special characters 
                // (such as space, "&", "+", "%") with HTML entities. 
                // ( 0 => "use strlen to find string length" ) 
                // remember to call curl_free() on the strings on the way out 
                char* key = curl_escape( pp[0] , 0 );
                char* val = curl_escape( pp[1] , 0 );

                postBuf << key << "=" << val << "&" ;
                pp += 2 ;
                // the cURL lib allocated the escaped versions of the 
                // param strings; we must free them here 
                curl_free( key ) ;
                curl_free( val ) ;
        }
        postBuf << std::flush ;
}

void curl_post(const char* url, const char** postArrayData)
{
        const char* targetUrl = url;

        // curl 를 초기화 한다.
        curl_global_init( CURL_GLOBAL_ALL ) ;

        // context 를 생성한다.
        CURL* ctx = curl_easy_init() ;
        if( NULL == ctx ){
                printf("curl context 생성 실패\n");
                return;
        }

        /* BEGIN: configure the handle: */
        // 쿠키 값을 비워주기( 혹시 쿠키를 받는 사이트일 경우 필요 )
        curl_easy_setopt(ctx, CURLOPT_COOKIEFILE, "");
        // 요청 url
        curl_easy_setopt( ctx , CURLOPT_URL,  targetUrl ) ;

        // 요청한 결과 data를 메모리에 받아 오기
        html_context_data data = {0, 0};

        curl_easy_setopt(ctx, CURLOPT_WRITEDATA, &data);
        curl_easy_setopt(ctx, CURLOPT_WRITEFUNCTION, callback_write_memory );
        // 데이터를 표준출력으로 내보내기
        // curl_easy_setopt( ctx , CURLOPT_WRITEDATA , stdout ) ; 

        // 헤더 셋팅하기
        curl_slist* header = NULL ;
        header = curl_slist_append( header , "User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; .NET CLR 1.0.3705) " ) ;
        header = curl_slist_append( header , "Content-Type: application/x-www-form-urlencoded" ) ;
        curl_easy_setopt( ctx , CURLOPT_HTTPHEADER , header ) ;

        // POST Data 설정  
        // notice the URL-unfriendly characters (such as "%" and "&") 
        // URL에서는 '%', '&', ' '와 같은 문자를 URL encoding 시켜줘야 한다. 
        // curl_escape 함수를 이용해서 인코딩할 수 있다.  
        std::ostringstream postBuf ;
        get_post_data( postBuf, postArrayData);
        const std::string postData = postBuf.str();
        curl_easy_setopt( ctx , CURLOPT_POSTFIELDS , postData.c_str() ) ;

        // post 방식으로 요청할 것인지 셋팅
        curl_easy_setopt( ctx , CURLOPT_POST , 1 ) ;

        // 사이트 실제 처리 요청
        CURLcode rc = curl_easy_perform( ctx ) ;
        if( CURLE_OK != rc ){
                std::cerr << '\t' << "에러 : " << curl_easy_strerror( rc ) << std::endl ;
        }
        // 쿠키 있으면 출력
        print_cookie( ctx );
        // html 리턴 코드 보기
        long statLong;
        curl_easy_getinfo( ctx, CURLINFO_HTTP_CODE, &statLong);
        // data 해당 페이지 출력
        std::cout << data.data << std::endl;
        // 사용한 메모리 해제
        free_html_context_data( &data );
        // 헤더 리스트 해제
        curl_slist_free_all( header ) ;
        // context 해제
        curl_easy_cleanup( ctx ) ;
        // lib 해제
        curl_global_cleanup() ;
}

[출처] libcurl post 요청 예제|작성자 규승

( http://blog.naver.com/laster40?Redirect=Log&logNo=107370315 )



------------------------------------------------------------------------------------------------------------------------------------------------------


어떤 분이 에러코드 뜬다고 올린 질문인데, 저는 에러를 띄우고 싶어서 한번 찾아봤어요. 그랬더니 원하는게 있긴 있네요 ㅎㅎㅎㅎㅎㅎㅎㅎ


동일한 질문이 있어서 갖고 왔어요, 이 질문 답변자 분의 말씀을 들어보니 curl_easy_perform의 return값을 확인해서 그 값이 틀릴 경우엔 생성했던 파일을 지우라네요, 결국은 미리 확인하는 방법은 일단 없는걸로,, 그렇다고 함수 하나 만들어서 미리 받아와 보기도 좀 그렇구요.. 일단 끝ㅋ


파일을 지우는 경우엔 별다른 문제는 없을 듯 하다. 대부분 call back함수 내에서 open과 close가 이루어지기 때문에 main에서 확인하여 지우는 것엔 별다른 문제는 없다. 


이제 solution격인 소스를 찾았으니깐 코딩 시작~~ 하기 전에 remove함수부터 찾고...

void GameImage::DownloadImage(string file_name) {
    string game_name;
    game_name = file_name.substr(file_name.find_last_of("/")+1);

    CURL *curl;
    FILE *fp;
    CURLcode res;
    string url = "http://site/"+game_name+".png";
    string outfilename = file_name+".png";
    cout<<"INFO; attempting to download "<<url<<"..."<<endl;
    curl = curl_easy_init();
    if (curl) {
        cout<<"INFO; downloading "<<url<<"..."<<endl;
        fp = fopen(outfilename.c_str(), "wb");
        cout<<"INFO; trying to open "<<outfilename<<" for file output"<<endl;
        if (fp == NULL) {
            cout<<"GameImage::DownloadImage; Couldn't open output file"<<endl;
            curl_easy_cleanup(curl);
            return;
        }
        curl_easy_setopt(curl, CURLOPT_URL, url.c_str());
        curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, GameImage::WriteData);
        curl_easy_setopt(curl, CURLOPT_WRITEDATA, fp);
        curl_easy_setopt(curl, CURLOPT_VERBOSE, 1);
        curl_easy_setopt(curl, CURLOPT_FAILONERROR, true);
        res = curl_easy_perform(curl);
        fclose(fp);

        if (res != CURLE_OK) {
            cout<<"GameImage::DownloadImage; Failed to download file"<<endl;
            remove(outfilename.c_str());
        }

        curl_easy_cleanup(curl);
    }
}

size_t GameImage::WriteData(void *ptr, size_t size, size_t nmemb, FILE *stream) {
    size_t written;
    written = fwrite(ptr, size, nmemb, stream);
    return written;
}

( http://stackoverflow.com/questions/4252533/libcurl-404-detection )



------------------------------------------------------------


remove 함수, 찾아보니깐 딱이네 ㅎㅎ

그동안 찾던 잘못된 URL에 대한 예외처리 해주러 고고~~


function
<cstdio>

remove

int remove ( const char * filename );
Remove file
Deletes the file whose name is specified in filename.

This is an operation performed directly on a file identified by its filename; No streams are involved in the operation.

Proper file access shall be available.

( http://www.cplusplus.com/reference/cstdio/remove/ )

저작자표시 비영리 (새창열림)

'소프트웨어' 카테고리의 다른 글

[javascript] chapter6. Objects _발번역  (0) 2014.01.22
[c++] ifndef / endif  (0) 2014.01.22
[curl] curl_easy_getinfo (1)  (0) 2014.01.21
[c++] file path 설정  (0) 2014.01.20
[ubuntu] T440P NVIDIA 드라이버 잡는 방법(bumblebee)  (0) 2014.01.06
    '소프트웨어' 카테고리의 다른 글
    • [javascript] chapter6. Objects _발번역
    • [c++] ifndef / endif
    • [curl] curl_easy_getinfo (1)
    • [c++] file path 설정
    개발자_이훈규
    개발자_이훈규
    혼자 꽁양꽁양 개발하면서 놀아요~ - 노트같은 블로그

    티스토리툴바