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) |