[C/C++] proxy、HTTP1.0、HTTP1.1に対応したソースコード取得の簡単なサンプル



インターネット上にC言語でソースコードをGETするサンプルは沢山ありましたが、Proxyに対応したものやHTTP1.1に対応したもの(暫定)が存在しなかったので紹介します。

スポンサードリンク

ソースコード

あるホストのWebページのソースコードを取得するプログラムです。

Proxyを利用しない場合は「#define SUPPORT_PROXY」を削除、HTTP1.1を利用しない場合は「#define HTTP_1_1」を削除してください。

#include <stdio.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <stdlib.h>
#include <unistd.h>
#include <netdb.h>
#include <string.h>

#define SUPPORT_PROXY
#define HTTP_1_1

int create_tcp_socket();
char *get_ip(char *host);
char *build_get_query(char *host, char *page);
void usage();

#define PAGE "/"
#define PORT 80
#define USERAGENT "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1)"

#define PROXY_HOST "xxx.xxx.xxx.xxx.xxx"
#define PROXY_PORT xxxxxx

int main(int argc, char **argv)
{
    struct sockaddr_in *remote;
    int sock;
    int tmpres;
    char *ip;
    char *get;
    char buf[BUFSIZ+1];
    char *host;
    char *page;

    if(argc == 1){
        usage();
        exit(2);
    }
    host = argv[1];
    if(argc > 2){
        page = argv[2];
    }else{
        page = PAGE;
    }
    sock = create_tcp_socket();
    ip = get_ip(host);
    fprintf(stderr, "IP is %s\n", ip);
    remote = (struct sockaddr_in *)malloc(sizeof(struct sockaddr_in *));
    remote->sin_family = AF_INET;
    tmpres = inet_pton(AF_INET, ip, (void *)(&(remote->sin_addr.s_addr)));
    if( tmpres < 0)
    {
        perror("Can't set remote->sin_addr.s_addr");
        exit(1);
    }else if(tmpres == 0)
    {
        fprintf(stderr, "%s is not a valid IP address\n", ip);
        exit(1);
    }
#ifdef SUPPORT_PROXY
    remote->sin_port = htons(PROXY_PORT);
#else
    remote->sin_port = htons(PORT);
#endif

    if(connect(sock, (struct sockaddr *)remote, sizeof(struct sockaddr)) < 0){
        perror("Could not connect");
        exit(1);
    }
    get = build_get_query(host, page);
    fprintf(stderr, "Query is:\n<<START>>\n%s<<END>>\n", get);

    //Send the query to the server
    int sent = 0;
    while(sent < strlen(get))
    {
        printf("body =[%s]\n",get);
        tmpres = send(sock, get+sent, strlen(get)-sent, 0);
        if(tmpres == -1){
            perror("Can't send query");
            exit(1);
        }
        sent += tmpres;
    }
    //now it is time to receive the page
    memset(buf, 0, sizeof(buf));
    int htmlstart = 0;
    char * htmlcontent;
    while((tmpres = recv(sock, buf, BUFSIZ, 0)) > 0){
        if(htmlstart == 0)
        {
            htmlcontent = strstr(buf, "\r\n\r\n");
            if(htmlcontent != NULL){
                htmlstart = 1;
                htmlcontent += 4;
            }
        }else{
            htmlcontent = buf;
        }
        if(htmlstart){
            fprintf(stdout, "%s", htmlcontent);
        }

        memset(buf, 0, tmpres);
    }
    if(tmpres < 0)
    {
        perror("Error receiving data");
    }
    free(get);
    free(remote);
    free(ip);
    close(sock);
    return 0;
}

void usage()
{
    fprintf(stderr, "利用方法: htmlget host [page]\n\
\thost: the website hostname. ex: coding.debuntu.org\n\
\tpage: the page to retrieve. ex: index.html, default: /\n");
}

int create_tcp_socket()
{
    int sock;
    if((sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0){
        perror("Can't create TCP socket");
        exit(1);
    }
    return sock;
}

char *get_ip(char *host)
{
    struct hostent *hent;
    int iplen = 15; //XXX.XXX.XXX.XXX
    char *ip = (char *)malloc(iplen+1);
    memset(ip, 0, iplen+1);
    printf("%s\n",host);
#ifdef SUPPORT_PROXY
    if((hent = gethostbyname(PROXY_HOST)) == NULL)
#else
    if((hent = gethostbyname(host)) == NULL)
#endif
    {
        herror("Can't get IP");
        exit(1);
    }
    if(inet_ntop(AF_INET, (void *)hent->h_addr_list[0], ip, iplen) == NULL)
    {
        perror("Can't resolve host");
        exit(1);
    }
    return ip;
}

char *build_get_query(char *host, char *page)
{
    char *query;
    char *getpage = page;
#ifdef HTTP_1_1
    char *tpl = "GET /%s HTTP/1.1\r\nHost: %s\r\nUser-Agent: %s\r\nConnection: close\r\n\r\n";
#else
    char *tpl = "GET /%s HTTP/1.0\r\nHost: %s\r\nUser-Agent: %s\r\n\r\n";
#endif
    if(getpage[0] == '/'){
        getpage = getpage + 1;
        fprintf(stderr,"Removing leading \"/\", converting %s to %s\n", page, getpage);
    }
    // -5 is to consider the %s %s %s in tpl and the ending \0
    query = (char *)malloc(strlen(host)+strlen(getpage)+strlen(USERAGENT)+strlen(tpl)-5);
    sprintf(query, tpl, getpage, host, USERAGENT);
    return query;
}

ビルド方法

g++ -o htmlget httpget.cpp

スポンサードリンク

結果

「ホスト名」と取得したい「ファイル名」を引数にすることでファイルが取得できます。

$ ./htmlget
利用方法: htmlget host [page]
host: the website hostname. ex: coding.debuntu.org
page: the page to retrieve. ex: index.html, default: /

$ ./htmlget uguisu.skr.jp index.html

スポンサードリンク