kbio_htget.c

最終更新:2009/12/19

kbio_htget.c

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 */
Copyright (C) KAKU PROJECT (2009)KAKU PROJECT (2009)