kbio_htget.c
最終更新:2009/12/19
001: /* 002: * kbio_htget.c 003: * BIO API から apr_socket を使う例 004: * HTTP/1.0 でWebサイトに接続してファイルに保存する。 005: * HTTP/1.1 にしないのは、チャンク形式に対応していないため。 006: */ 007: 008: #define USAGE "Usage: kbio_htget <uri> <out_filename>" 009: 010: #include "apr_general.h" 011: 012: #include "apr_errno.h" 013: #include "apr_strings.h" 014: #include "apr_uri.h" 015: #include "apr_tables.h" 016: 017: #include "openssl/bio.h" 018: #include "bio_apr_socket.h" 019: #include "mystab.h" 020: #include "myht_util.h" 021: 022: void trim_CRLF(char *line) { 023: int i=0; 024: int len = 0; 025: if (!line) 026: return; 027: len = strlen(line); 028: for (i=len-1; i>=0; i--) { 029: if (line[i] == '\r' || line[i] == '\n') { 030: line[i] = '\0'; 031: } else { 032: break; 033: } 034: } 035: } 036: 037: /* 概要:entity-header と CRLF の読み出し 038: * 返り値: 039: * 成功時:1 040: * 失敗時:0 最後の CRLF を見つけられなかった時 041: * メモ:読み出した entity-header は f に渡される 042: * void f (const char *line, void *ctx); 043: */ 044: 045: int BIO_read_entity_headers_CRLF_do ( 046: BIO *in /* 入力ストリーム */ 047: , void *f 048: , void *ctx 049: ) { 050: void (*func)(char *, void *) = f; 051: char line[1024]; 052: while (BIO_gets(in, line, sizeof(line)) >= 0) { 053: trim_CRLF(line); 054: if (line[0] == '\0') { 055: return 1; 056: } 057: /* 取り出した entity-header の処理 */ 058: 059: if (func) 060: (*func)(line, ctx); 061: } 062: return 0; 063: } 064: int apr_my_main ( 065: int ac 066: , char **av 067: , apr_file_t * astdin 068: , apr_file_t * astdout 069: , apr_file_t * astderr 070: , apr_pool_t * pool 071: ) { 072: 073: int error_flag = 0; 074: apr_status_t rv = APR_SUCCESS; 075: 076: 077: char *uri_str = NULL; 078: 079: apr_uri_t uri; 080: 081: char *hostname = NULL; 082: int port = 0; 083: char *out_filename = NULL; 084: 085: BIO *bio = NULL; 086: BIO *bio_out = NULL; 087: 088: apr_table_t * rsp_headers = NULL; 089: 090: if (ac < 3) { 091: apr_file_printf(astderr, "%s\n", USAGE); 092: error_flag = 1; 093: goto _FINALLY_; 094: } 095: 096: uri_str = av[1]; 097: out_filename = av[2]; 098: 099: /* URI のパース */ 100: 101: if (! my_uri_parse(pool, uri_str, &uri)) { 102: apr_file_printf(astderr, "ERROR: uri [%s] ", uri_str); 103: error_flag = 1; 104: goto _FINALLY_; 105: } 106: 107: hostname = uri.hostname; 108: port = uri.port; 109: 110: /* サーバへの接続 */ 111: bio = bio_apr_socket_connect(hostname, port, pool); 112: if (!bio) { 113: apr_file_printf(astderr, "ERROR: bio_apr_socket_connect [%s:%d] ", hostname, port); 114: error_flag = 1; 115: goto _FINALLY_; 116: } 117: 118: /* 出力ファイルのオープン */ 119: bio_out = BIO_new_file(out_filename, "w"); 120: if (!bio_out) { 121: apr_file_printf(astderr, "ERROR: BIO_new_file [%s] ", out_filename); 122: error_flag = 1; 123: goto _FINALLY_; 124: } 125: 126: /* リクエストの送信 */ 127: { 128: int nbytes = 0; 129: char *req = apr_pstrcat(pool, "GET ", uri.path, " HTTP/1.0\r\n", NULL); 130: if ((!strcmp(uri.scheme, "http") && uri.port == 80) || 131: (!strcmp(uri.scheme, "https") && uri.port == 443) 132: ) { 133: req = apr_pstrcat(pool, req, "Host: ", uri.hostname, "\r\n", NULL); 134: } else { 135: req = apr_pstrcat(pool, req, "Host: ", uri.hostname, ":", uri.port_str, 136: "\r\n", NULL); 137: } 138: req = apr_pstrcat(pool, req, "Accept: */*\r\n", NULL); 139: req = apr_pstrcat(pool, req, "User-Agent: khtget/0.1\r\n\r\n", NULL); 140: 141: nbytes = BIO_write(bio, req, strlen(req)); 142: if (nbytes <= 0) { 143: apr_file_printf(astderr, "ERROR: BIO_write "); 144: error_flag = 1; 145: goto _FINALLY_; 146: } 147: } 148: 149: /* バッファリングフィルタ */ 150: { 151: bio = BIO_push(BIO_new(BIO_f_buffer()), bio); 152: if (!bio) { 153: apr_file_printf(astderr, "ERROR: BIO_push "); 154: error_flag = 1; 155: goto _FINALLY_; 156: } 157: } 158: 159: /* レスポンスラインの受信 */ 160: { 161: char rsp_line[1024]; 162: char *rsp_version=NULL; 163: char *status_str=NULL; 164: char *reason_phrase=NULL; 165: int ret = 0; 166: 167: if (BIO_gets(bio, rsp_line, sizeof(rsp_line)) < 0) { 168: error_flag = 1; 169: goto _FINALLY_; 170: } 171: trim_CRLF(rsp_line); 172: ret = read_rsp_line(rsp_line, 173: &rsp_version, &status_str, &reason_phrase, ' '); 174: if (ret < 3) { 175: apr_file_printf(astderr, "ERROR: read_rsp_line "); 176: error_flag = 1; 177: goto _FINALLY_; 178: } 179: apr_file_printf(astdout, "[%s] [%s] [%s]\n", 180: rsp_version, status_str, reason_phrase); 181: } 182: 183: /* レスポンスヘッダの受信 */ 184: 185: rsp_headers = apr_table_make(pool, 10); 186: { 187: int ret = BIO_read_entity_headers_CRLF_do (bio, set_entity_header_to_tab, 188: rsp_headers); 189: if (! ret) { 190: apr_file_printf(astderr, "ERROR: BIO_read_entity_headers_CRLF_do "); 191: error_flag = 1; 192: goto _FINALLY_; 193: } 194: } 195: 196: /* レスポンスヘッダの表示 */ 197: 198: apr_table_do(disp_tab, astdout, rsp_headers, NULL); 199: 200: /* レスポンスボディの受信〜ファイル出力 */ 201: 202: { 203: char buf[1024]; 204: while (1) { 205: int nbytes = BIO_read(bio, buf, sizeof(buf)); 206: if (nbytes <= 0) { 207: break; 208: } 209: nbytes = BIO_write(bio_out, buf, nbytes); 210: if (nbytes < 0) { 211: break; 212: } 213: } 214: } 215: 216: _FINALLY_: 217: 218: if (bio) { 219: BIO_free_all(bio); 220: bio = NULL; 221: } 222: if (bio_out) { 223: BIO_free_all(bio_out); 224: bio_out = NULL; 225: } 226: 227: if (rv != APR_SUCCESS) { 228: char error_buf[80]; 229: apr_file_printf(astderr, "ERROR: %s\n", 230: apr_strerror(rv, error_buf, sizeof(error_buf))); 231: } 232: 233: if (error_flag) { 234: apr_file_printf(astderr, "failed!\n"); 235: return 1; /* 異常終了 */ 236: } 237: 238: apr_file_printf(astdout, "\ndone.\n"); 239: 240: return 0; /* 正常終了 */ 241: 242: } /* end of main */
KAKU PROJECT (2009) |