/* * kmyio_htget2.c * HTTP/1.1 でWebサイトに接続してファイルに保存する。 */ #define USAGE "Usage: kmtio_htget2 " #include #include "apr_general.h" #include "apr_lib.h" #include "apr_errno.h" #include "apr_strings.h" #include "apr_uri.h" #include "apr_tables.h" #include "mystab.h" #include "myio_chunk.h" #include "myio_apr.h" #include "myht_util.h" int apr_my_main ( int ac , char **av , apr_file_t * astdin , apr_file_t * astdout , apr_file_t * astderr , apr_pool_t * pool ) { int error_flag = 0; apr_status_t rv = APR_SUCCESS; char *uri_str = NULL; char *out_filename = NULL; apr_uri_t uri; char *hostname = NULL; int port = 0; MYIO *io = NULL; MYIO *out = NULL; apr_table_t * rsp_headers = NULL; int rsp_clen = -1; int chunked = 0; if (ac < 3) { apr_file_printf(astderr, "%s\n", USAGE); error_flag = 1; goto _FINALLY_; } uri_str = av[1]; out_filename = av[2]; if (! my_uri_parse(pool, uri_str, &uri)) { apr_file_printf(astderr, "ERROR: uri [%s] ", uri_str); error_flag = 1; goto _FINALLY_; } hostname = uri.hostname; port = uri.port; /* サーバへの接続 */ io = MYIO_sock_connect(hostname, port, pool); if (!io) { apr_file_printf(astderr, "ERROR: connect [%s:%d] ", hostname, port); error_flag = 1; goto _FINALLY_; } /* 出力ファイルのオープン */ out = MYIO_fp_open(out_filename, APR_FOPEN_WRITE|APR_FOPEN_CREATE|APR_FOPEN_BINARY|APR_FOPEN_TRUNCATE, APR_OS_DEFAULT, pool); if (!out) { apr_file_printf(astderr, "ERROR: file open [%s] ", out_filename); error_flag = 1; goto _FINALLY_; } /* リクエストの送信 */ { int nbytes = 0; char *req = apr_pstrcat(pool, "GET ", uri.path, " HTTP/1.1\r\n", NULL); if (uri.port == 80) { req = apr_pstrcat(pool, req, "Host: ", uri.hostname, "\r\n", NULL); } else { req = apr_pstrcat(pool, req, "Host: ", uri.hostname, ":", uri.port_str, "\r\n", NULL); } req = apr_pstrcat(pool, req, "Accept: */*\r\n", NULL); /* req = apr_pstrcat(pool, req, "Accept-Encoding: gzip, compress, deflate, identity\r\n", NULL); req = apr_pstrcat(pool, req, "Connection: close\r\n", NULL); */ req = apr_pstrcat(pool, req, "User-Agent: khtget/0.1\r\n\r\n", NULL); nbytes = MYIO_write(io, req, strlen(req)); if (nbytes <= 0) { error_flag = 1; goto _FINALLY_; } } /* レスポンスラインの受信 */ { char rsp_line[1024]; char *rsp_version=NULL; char *status_str=NULL; char *reason_phrase=NULL; int ret = 0; if (MYIO_gets(io, rsp_line, sizeof(rsp_line)) < 0) { error_flag = 1; goto _FINALLY_; } ret = read_rsp_line(rsp_line, &rsp_version, &status_str, &reason_phrase, ' '); if (ret < 3) { apr_file_printf(astderr, "ERROR: read_rsp_line "); error_flag = 1; goto _FINALLY_; } apr_file_printf(astdout, "[%s] [%s] [%s]\n", rsp_version, status_str, reason_phrase); } /* レスポンスヘッダの受信 */ rsp_headers = apr_table_make(pool, 10); { int ret = MYIO_read_entity_headers_CRLF_do(io, set_entity_header_to_tab, rsp_headers); if (! ret) { apr_file_printf(astderr, "ERROR: bio_read_entity_headers_CRLF_do "); error_flag = 1; goto _FINALLY_; } } /* レスポンスヘッダの表示 */ apr_table_do(disp_tab, astdout, rsp_headers, NULL); /* コンテンツレングス、転送エンコーディングのチェック */ { char *tmp = (char*)apr_table_get(rsp_headers, "Content-Length"); if (!tmp) { rsp_clen = -1; } else { rsp_clen = atoi(tmp); } tmp = (char*)apr_table_get(rsp_headers, "Transfer-Encoding"); if (tmp && !strcmp(tmp, "chunked")) { chunked = 1; } } /* レスポンスの受信〜ファイル出力 */ if (chunked) { int nbytes = MYIO_decode_chunked_body(io, out); if (nbytes < 0) { apr_file_printf(astderr, "ERROR: bio_decode_chunked_body "); error_flag = 1; goto _FINALLY_; } apr_table_set(rsp_headers, "Content-Length", apr_itoa(pool, nbytes)); rsp_clen = nbytes; apr_table_unset(rsp_headers, "Transfer-Encoding"); chunked = 0; } else { if (rsp_clen > 0) { int nbytes = MYIO_move(io, rsp_clen, out); if (nbytes != rsp_clen) { apr_file_printf(astderr, "ERROR: MYIO_move "); error_flag = 1; goto _FINALLY_; } } } _FINALLY_: if (out) { MYIO_fp_close(out); out = NULL; } if (io) { MYIO_sock_close(io); io = NULL; } if (rv != APR_SUCCESS) { char error_buf[80]; apr_file_printf(astderr, "ERROR: %s\n", apr_strerror(rv, error_buf, sizeof(error_buf))); } if (error_flag) { apr_file_printf(astderr, "failed!\n"); return 1; /* 異常終了 */ } apr_file_printf(astdout, "\ndone.\n"); return 0; /* 正常終了 */ } /* end of main */