mybb.c
最終更新:2009/12/16
001: /* mybb.c
002: * Bucket Brigade のサンプル
003: * (1)ストリームでのデータ操作関数
004: * ・ストリーム間のバイト単位での移動
005: * ・ストリームからの行単位での切り出し
006: * ・ストリームからファイルへの書き出し
007: * (2)チャンク形式のデコーダ関数
008: */
009:
010: #include <stdlib.h>
011:
012: #include "apr_general.h"
013: #include "apr_buckets.h"
014: #include "apr_file_io.h"
015: #include "apr_strings.h"
016: #include "mybb.h"
017:
018: #if 0
019: /*
020: * ストリーム bb1 から size バイト分の buckets をバッファに移す。
021: * 返り値は実際に移したバイト数。
022: * size<=0 の時は何もしない。0が返る。
023: * ストリーム bb1 が空の時も何もしない。0が返る。
024: * 終了後は、ストリーム bb1 の先頭 size バイト分がなくなる。
025: */
026:
027: int move_bytes_from_bb_to_buf (
028: apr_bucket_brigade *bb1
029: , apr_size_t size
030: , char *buf
031: ) {
032: int ret=0;
033: apr_size_t remain=size;
034: apr_bucket *b=NULL;
035:
036: if (size <=0) {
037: return 0;
038: }
039:
040: if (APR_BRIGADE_EMPTY(bb1)) {
041: return 0;
042: }
043:
044: if(0)puts("#move_bytes_from_bb(1)");
045: /* for (b = APR_BRIGADE_FIRST(bb1); b != APR_BRIGADE_SENTINEL(bb1); b = APR_BUCKET_NEXT(b)) {
046: バケット b をストリーム bb1 から削除し、bb2 に挿入した場合に、APR_BUCKET_NEXT(b) は bb2 での
047: 位置関係に依存したものとなるため、ループの書き方はいつもと少し違う。毎回先頭のバケットを
048: チェックする。
049: */
050: for (b = APR_BRIGADE_FIRST(bb1); b != APR_BRIGADE_SENTINEL(bb1); b = APR_BRIGADE_FIRST(bb1)) {
051: if(0)printf("(1)remain=[%d], b->length=[%d], metadata=[%d]\n", remain, b->length, APR_BUCKET_IS_METADATA(b));
052: if (remain <= 0) {
053: break;
054: }
055:
056: if(0)puts("#move_bytes_from_bb(2)");
057: if (b->length == 0) {
058: /* 削除しておく */
059: APR_BUCKET_REMOVE(b);
060: continue;
061: }
062:
063: if(0)puts("#move_bytes_from_bb(3)");
064: if (APR_BUCKET_IS_SOCKET(b)) {
065: char *buf = NULL;
066: apr_size_t len=0;
067: apr_bucket_read(b, &buf, &len, APR_BLOCK_READ); /* 読み飛ばすだけ。 */
068:
069: /* バケットがソケットの場合には read しないとストリームにデータが積まれないらしい。b->length も UNKNOWN(-1)。 */
070: }
071:
072: if(0)puts("#move_bytes_from_bb(4)");
073: if(0)printf("(2)remain=[%d], b->length=[%d], metadata=[%d]\n", remain, b->length, APR_BUCKET_IS_METADATA(b));
074:
075:
076: if (b->length > remain) {
077: if(0)printf("(3)remain=[%d], b->length=[%ld], metadata=[%d]\n", remain, b->length, APR_BUCKET_IS_METADATA(b));
078: /* b を remain バイト分と b->length-remain バイト分に分割 */
079: apr_bucket_split(b, remain);
080: /* remain バイト分を bb1 から削除 */
081: APR_BUCKET_REMOVE(b);
082: /* remain バイト分をバッファコピー */
083: apr_bucket_read(b, buf+ret, remain, 1);
084: /* 移動した分をカウント */
085: ret += remain;
086: /* ループを抜ける */
087: break;
088: }
089:
090: if(0)puts("#move_bytes_from_bb(8)");
091: /* b を bb1 から削除 */
092: APR_BUCKET_REMOVE(b);
093: if(0)puts("#move_bytes_from_bb(9)");
094: /* b を bb2 に追加 */
095: apr_bucket_read(b, buf+ret, b->length, 1);
096: if(0)puts("#move_bytes_from_bb(10)");
097: /* 移動した分をカウント */
098: ret += b->length;
099: remain -= b->length;
100: if(0)printf("remain=[%d]\n", remain);
101: }
102:
103: if(0)puts("#move_bytes_from_bb(11)");
104: return ret;
105: }
106: #endif
107:
108: /*
109: * ストリーム bb1 から size バイト分の buckets をストリーム bb2 に移す。
110: * 返り値は実際に移したバイト数。
111: * size<=0 の時は何もしない。0が返る。
112: * ストリーム bb1 が空の時も何もしない。0が返る。
113: * 終了後は、ストリーム bb1 の先頭 size バイト分がなくなる。ストリーム bb2 は後尾に size バイト分増えている。
114: */
115:
116: int move_bytes_from_bb (apr_bucket_brigade *bb1, apr_size_t size, apr_bucket_brigade *bb2) {
117: int ret=0;
118: apr_size_t remain=size;
119: apr_bucket *b=NULL;
120:
121: if (size <=0) {
122: return 0;
123: }
124:
125: if (APR_BRIGADE_EMPTY(bb1)) {
126: return 0;
127: }
128:
129: if(0)puts("#move_bytes_from_bb(1)");
130: /* for (b = APR_BRIGADE_FIRST(bb1); b != APR_BRIGADE_SENTINEL(bb1); b = APR_BUCKET_NEXT(b)) {
131: バケット b をストリーム bb1 から削除し、bb2 に挿入した場合に、APR_BUCKET_NEXT(b) は bb2 での
132: 位置関係に依存したものとなるため、ループの書き方はいつもと少し違う。毎回先頭のバケットを
133: チェックする。
134: */
135: for (b = APR_BRIGADE_FIRST(bb1); b != APR_BRIGADE_SENTINEL(bb1); b = APR_BRIGADE_FIRST(bb1)) {
136: if(0)printf("(1)remain=[%d], b->length=[%d], metadata=[%d]\n", remain, b->length, APR_BUCKET_IS_METADATA(b));
137: if (remain <= 0) {
138: break;
139: }
140:
141: if(0)puts("#move_bytes_from_bb(2)");
142: if (b->length == 0) {
143: /* 削除しておく */
144: APR_BUCKET_REMOVE(b);
145: continue;
146: }
147:
148: if(0)puts("#move_bytes_from_bb(3)");
149: if (APR_BUCKET_IS_SOCKET(b)) {
150: const char *buf = NULL;
151: apr_size_t len=0;
152: apr_bucket_read(b, &buf, &len, APR_BLOCK_READ); /* 読み飛ばすだけ。 */
153:
154: /* バケットがソケットの場合には read しないとストリームにデータが積まれないらしい。b->length も UNKNOWN(-1)。 */
155: }
156:
157: if(0)puts("#move_bytes_from_bb(4)");
158: if(0)printf("(2)remain=[%d], b->length=[%d], metadata=[%d]\n", remain, b->length, APR_BUCKET_IS_METADATA(b));
159:
160:
161: if (b->length > remain) {
162: if(0)printf("(3)remain=[%d], b->length=[%d], metadata=[%d]\n", remain, b->length, APR_BUCKET_IS_METADATA(b));
163: /* b を remain バイト分と b->length-remain バイト分に分割 */
164: apr_bucket_split(b, remain);
165: if(0)puts("#move_bytes_from_bb(5)");
166: /* remain バイト分を bb1 から削除 */
167: APR_BUCKET_REMOVE(b);
168: if(0)puts("#move_bytes_from_bb(6)");
169: /* remain バイト分を bb2 に追加 */
170: APR_BRIGADE_INSERT_TAIL(bb2, b);
171: if(0)puts("#move_bytes_from_bb(7)");
172: /* 移動した分をカウント */
173: ret += remain;
174: /* ループを抜ける */
175: break;
176: }
177:
178: if(0)puts("#move_bytes_from_bb(8)");
179: /* b を bb1 から削除 */
180: APR_BUCKET_REMOVE(b);
181: if(0)puts("#move_bytes_from_bb(9)");
182: /* b を bb2 に追加 */
183: APR_BRIGADE_INSERT_TAIL(bb2, b);
184: if(0)puts("#move_bytes_from_bb(10)");
185: /* 移動した分をカウント */
186: ret += b->length;
187: remain -= b->length;
188: if(0)printf("remain=[%d]\n", remain);
189: }
190:
191: if(0)puts("#move_bytes_from_bb(11)");
192: return ret;
193: }
194:
195:
196: /*
197: * LF で終わる一行分の文字列をストリーム bb から切り出す。
198: * 最後のLF もしくは CRLF はヌル文字で置き換えられる。
199: * 返り値の文字列は必ずヌル文字で終わる
200: * 終了後は、ストリーム bb から先頭の LF で終わる一行分のデータがなくなる。
201: * apr_brigade_split_line でエラーになった場合やサイズが大きすぎる場合(MAX_LINE_SIZE 以上)は NULL が返る。
202: * 空行の場合は、"" が返る。
203: */
204:
205: char *get_line_from_bb (apr_bucket_brigade *bb)
206: {
207: apr_bucket *b = NULL;
208: char *ret;
209: char *p = NULL;
210: apr_size_t len=0;
211: apr_bucket_brigade *tmp_bb=apr_brigade_create(bb->p, bb->bucket_alloc);
212:
213: if (APR_SUCCESS != apr_brigade_split_line(tmp_bb, bb, APR_BLOCK_READ, MAX_LINE_SIZE)) {
214: return NULL;
215: }
216:
217:
218: if (APR_BRIGADE_EMPTY(tmp_bb)) { /* こういうケースはある? */
219: return NULL;
220: }
221:
222: p = ret = apr_palloc(bb->p, MAX_LINE_SIZE);
223:
224: for (b = APR_BRIGADE_FIRST(tmp_bb); b != APR_BRIGADE_SENTINEL(tmp_bb); b = APR_BUCKET_NEXT(b)) {
225: const char *buf = NULL;
226: apr_size_t buf_len;
227:
228:
229: if (0 == b->length) {
230: continue;
231: }
232:
233: apr_bucket_read(b, &buf, &buf_len, APR_BLOCK_READ);
234: if (p-ret+buf_len >= MAX_LINE_SIZE) {
235: return NULL; /* 長すぎる時も NULL を返す。が、apr_brigade_split_line で成功した場合はこういうケースはないのかもしれない */
236: }
237:
238: memcpy(p, buf, buf_len);
239: p += buf_len;
240: }
241:
242: *p = '\0'; /* 必ずヌル文字で終端 */
243:
244: len = p-ret;
245:
246: if (len > 0 && *(p-1) == '\n') { /* 行末の LF はヌル文字に */
247: *(p-1) = '\0';
248: }
249: if (len > 1 && *(p-2) == '\r') { /* 行末の CR はヌル文字に */
250: *(p-2) = '\0';
251: }
252:
253: apr_brigade_destroy(tmp_bb); /* 一応デストロイしておく。*/
254:
255: return ret;
256: }
257:
258: /*
259: * 概要:ストリームの中身をファイルに書き込む。バイト数指定なし。
260: * ストリームの中身は変更なし。
261: */
262:
263: void write_from_bb_to_fp (apr_bucket_brigade *bb, apr_file_t *fp) {
264: apr_bucket *b = NULL;
265: const char *buf = NULL;
266: apr_size_t len=0;
267: for (b = APR_BRIGADE_FIRST(bb); b != APR_BRIGADE_SENTINEL(bb); b = APR_BUCKET_NEXT(b)) {
268: if (0 == b->length) {
269: continue;
270: }
271: apr_bucket_read(b, &buf, &len, APR_BLOCK_READ);
272: if(0)printf("len=[%d], b->length=[%d], metadata=[%d]\n", len, b->length, APR_BUCKET_IS_METADATA(b));
273:
274: apr_file_write(fp, buf, &len);
275: }
276: }
277:
278: /*
279: * ストリーム bb1 から size バイト分の buckets をファイルに書き込む。
280: * 返り値は実際に移したバイト数。
281: * size<=0 の時は何もしない。0が返る。
282: * ストリーム bb1 が空の時も何もしない。0が返る。
283: * 終了後は、ストリーム bb1 の先頭 size バイト分がなくなる。
284: */
285:
286: int move_bytes_from_bb_to_fp (apr_bucket_brigade *bb1, apr_size_t size, apr_file_t *fp) {
287: int ret=0;
288: apr_size_t remain=size;
289: apr_bucket *b=NULL;
290:
291: if (size <=0) {
292: return 0;
293: }
294:
295: if (APR_BRIGADE_EMPTY(bb1)) {
296: return 0;
297: }
298:
299:
300: /* for (b = APR_BRIGADE_FIRST(bb1); b != APR_BRIGADE_SENTINEL(bb1); b = APR_BUCKET_NEXT(b)) {
301: バケット b をストリーム bb1 から削除し、bb2 に挿入した場合に、APR_BUCKET_NEXT(b) は bb2 での
302: 位置関係に依存したものとなるため、ループの書き方はいつもと少し違う。毎回先頭のバケットを
303: チェックする。
304: */
305: for (b = APR_BRIGADE_FIRST(bb1); b != APR_BRIGADE_SENTINEL(bb1); b = APR_BRIGADE_FIRST(bb1)) {
306:
307: const char *buf = NULL;
308: apr_size_t len=0;
309:
310:
311: if(0)printf("(1)remain=[%d], b->length=[%d], metadata=[%d]\n", remain, b->length, APR_BUCKET_IS_METADATA(b));
312: if (remain <= 0) {
313: break;
314: }
315:
316: if(0)printf("(1.1)remain=[%d], b->length=[%d], metadata=[%d]\n", remain, b->length, APR_BUCKET_IS_METADATA(b));
317: if (b->length == 0) {
318: /* 削除しておく */
319: APR_BUCKET_REMOVE(b);
320: continue;
321: }
322:
323: if(0)printf("(1.2)remain=[%d], b->length=[%d], metadata=[%d]\n", remain, b->length, APR_BUCKET_IS_METADATA(b));
324: if (APR_BUCKET_IS_SOCKET(b)) {
325: apr_bucket_read(b, &buf, &len, APR_BLOCK_READ); /* 読み飛ばすだけ。 */
326: /* バケットがソケットの場合にはサイズが不明(b->length == (-1))。
327: * read しないと実際のデータが積まれず、サイズが確定しない。
328: */
329: }
330:
331: if(0)printf("(2)remain=[%d], b->length=[%d], metadata=[%d]\n", remain, b->length, APR_BUCKET_IS_METADATA(b));
332:
333:
334: if (b->length > remain) {
335: if(0)printf("(3)remain=[%d], b->length=[%d], metadata=[%d]\n", remain, b->length, APR_BUCKET_IS_METADATA(b));
336: /* b を remain バイト分と b->length-remain バイト分に分割 */
337: apr_bucket_split(b, remain);
338: }
339:
340: /* remain バイト分を bb1 から削除 */
341: APR_BUCKET_REMOVE(b);
342: /* remain バイト分をファイルに書き出し */
343: apr_bucket_read(b, &buf, &len, APR_BLOCK_READ);
344: apr_file_write(fp, buf, &len);
345:
346: /* 書き出した分をカウント */
347: ret += len;
348: remain -= len;
349:
350: if(0)printf("remain=[%d]\n", remain);
351: }
352:
353: return ret;
354: }
355:
356: /*
357: * 以下、チャンク形式のデコーダ関数
358: */
359:
360: /* -- MEMO --
361: * From RFC 2616 Section 3.6.1
362: * Chunked-Body = *chunk
363: * last-chunk
364: * trailer
365: * CRLF
366: *
367: * chunk = chunk-size [ chunk-extension ] CRLF
368: * chunk-data CRLF
369: * chunk-size = 1*HEX
370: * last-chunk = 1*("0") [ chunk-extension ] CRLF
371: *
372: * chunk-extension= *( ";" chunk-ext-name [ "=" chunk-ext-val ] )
373: * chunk-ext-name = token
374: * chunk-ext-val = token | quoted-string
375: * chunk-data = chunk-size(OCTET)
376: * trailer = *(entity-header CRLF)
377: *
378: * From RFC 2616 Section 19.4.6
379: * length := 0
380: * read chunk-size, chunk-extension (if any) and CRLF
381: * while (chunk-size > 0) {
382: * read chunk-data and CRLF
383: * append chunk-data to entity-body
384: * length := length + chunk-size
385: * read chunk-size and CRLF
386: * }
387: * read entity-header
388: * while (entity-header not empty) {
389: * append entity-header to existing header fields
390: * read entity-header
391: * }
392: * Content-Length := length
393: * Remove "chunked" from Transfer-Encoding
394: *
395: */
396:
397: /* 概要:bb1 からの、chunk-size と CRLF の読み出し
398: * 返り値:
399: * 成功時:移動した chunk-size (0以上)
400: * 失敗時:-1
401: * メモ:chunk-extension は無視する。
402: */
403:
404: apr_size_t read_chunk_size_CRLF (apr_bucket_brigade *bb) {
405: apr_size_t chunk_size = 0;
406:
407: char *line = get_line_from_bb(bb);
408:
409: if (! line)
410: return -1;
411:
412: if (line) {
413: char *endptr=NULL;
414: errno = 0;
415: /* 16進数の文字列をパースする。
416: * ・strtol では、"0x" で始まる場合も許容されることに注意
417: * ・strtol では、16進数の文字の後に続く文字は無視されることにも注意。
418: * 従って、chunk-extension が存在しても無視される。
419: *
420: * XXX
421: * long int から apr_size_t への変換は危険かもしれない。
422: */
423: chunk_size = (apr_size_t)strtol(line, &endptr, 16);
424: if (errno) {
425: return -1;
426: }
427: }
428:
429: return chunk_size;
430: }
431:
432: /* 概要:bb1 からの、chunk-data の bb2 への移動と CRLF の読み出し
433: * 返り値:
434: * 成功時:移動したバイト数(0以上)。
435: * 失敗時:-1
436: */
437:
438: int read_chunk_data_CRLF(apr_bucket_brigade *bb1, apr_size_t size, apr_bucket_brigade *bb2) {
439: int length = 0;
440: char *line = NULL;
441: if ((length = move_bytes_from_bb(bb1, size, bb2)) < 0) {
442: return -1;
443: }
444: if (size != length) {
445: return -1;
446: }
447: if ((line = get_line_from_bb(bb1)) == NULL) {
448: return -1;
449: }
450: if (strcmp(line, "")) {
451: return -1;
452: }
453: return length;
454: }
455:
456: /* 概要:bb1 からの、entity-header と CRLF の読み出し
457: * 返り値:
458: * 成功時:1
459: * 失敗時:0 最後の CRLF を見つけられなかった時
460: * メモ:読み出した entity-header は無視する。
461: */
462:
463: int read_entity_header_CRLF(apr_bucket_brigade *bb1) {
464: char *line=NULL;
465: while ((line = get_line_from_bb(bb1))!=NULL) {
466: if (!strcmp(line, "")) {
467: return 1;
468: }
469: /*
470: * この位置で、見つけた entity-header に関する何らかの処理(パースして key/value をテーブル
471: * に保存など)を行なう。ここでは無視する。
472: */
473: }
474: return 0;
475: }
476:
477: #define read_trailer_CRLF read_entity_header_CRLF
478:
479: /* 概要:チャンク形式データのデコード
480: * パラメータ
481: * IN bb1 : デコード対象のデータを持つストリーム
482: * OUT bb2 : デコード後のデータを保管するストリーム
483: * 返り値:コンテンツの長さ(0以上)。デコード失敗時は -1
484: */
485:
486: int decode_chunked_body (apr_bucket_brigade *bb1, apr_bucket_brigade *bb2) {
487: int length = 0;
488: int chunk_size=0;
489:
490: while ((chunk_size = read_chunk_size_CRLF(bb1)) > 0) {
491: if (read_chunk_data_CRLF(bb1, chunk_size, bb2) < 0) {
492: return -1;
493: }
494: length += chunk_size;
495: }
496:
497: if (chunk_size < 0) { /* last-chunk がなかった */
498: return -1;
499: }
500:
501: if (read_trailer_CRLF(bb1) == 0) { /* trailer と最後の CRLF の読み出し */
502: return -1;
503: }
504:
505: return length;
506: }
507:
508: /*
509: * ストリーム bb1 から size バイト分の buckets をソケットに書き込む。
510: * 返り値は実際に移したバイト数。
511: * size<=0 の時は何もしない。0が返る。
512: * ストリーム bb1 が空の時も何もしない。0が返る。
513: * 終了後は、ストリーム bb1 の先頭 size バイト分がなくなる。
514: */
515:
516: int move_bytes_from_bb_to_s (apr_bucket_brigade *bb1, apr_size_t size, apr_socket_t *s) {
517: int ret=0;
518: apr_size_t remain=size;
519: apr_bucket *b=NULL;
520:
521: if (size <=0) {
522: return 0;
523: }
524:
525: if (APR_BRIGADE_EMPTY(bb1)) {
526: return 0;
527: }
528:
529:
530: /* for (b = APR_BRIGADE_FIRST(bb1); b != APR_BRIGADE_SENTINEL(bb1); b = APR_BUCKET_NEXT(b)) {
531: バケット b をストリーム bb1 から削除し、bb2 に挿入した場合に、APR_BUCKET_NEXT(b) は bb2 での
532: 位置関係に依存したものとなるため、ループの書き方はいつもと少し違う。毎回先頭のバケットを
533: チェックする。
534: */
535: for (b = APR_BRIGADE_FIRST(bb1); b != APR_BRIGADE_SENTINEL(bb1); b = APR_BRIGADE_FIRST(bb1)) {
536:
537: const char *buf = NULL;
538: apr_size_t len=0;
539:
540:
541: if(0)printf("(1)remain=[%d], b->length=[%d], metadata=[%d]\n", remain, b->length, APR_BUCKET_IS_METADATA(b));
542: if (remain <= 0) {
543: break;
544: }
545:
546: if (b->length == 0) {
547: /* 削除しておく */
548: APR_BUCKET_REMOVE(b);
549: continue;
550: }
551:
552: if (APR_BUCKET_IS_SOCKET(b)) {
553: apr_bucket_read(b, &buf, &len, APR_BLOCK_READ); /* 読み飛ばすだけ。 */
554: /* バケットがソケットの場合にはサイズが不明(b->length == (-1))。
555: * read しないと実際のデータが積まれず、サイズが確定しない。
556: */
557: }
558:
559: if(0)printf("(2)remain=[%d], b->length=[%d], metadata=[%d]\n", remain, b->length, APR_BUCKET_IS_METADATA(b));
560:
561:
562: if (b->length > remain) {
563: if(0)printf("(3)remain=[%d], b->length=[%d], metadata=[%d]\n", remain, b->length, APR_BUCKET_IS_METADATA(b));
564: /* b を remain バイト分と b->length-remain バイト分に分割 */
565: apr_bucket_split(b, remain);
566: }
567:
568: /* remain バイト分を bb1 から削除 */
569: APR_BUCKET_REMOVE(b);
570: /* remain バイト分をファイルに書き出し */
571: apr_bucket_read(b, &buf, &len, APR_BLOCK_READ);
572: if(0)fwrite(buf, len, 1, stdout);
573: apr_socket_send(s, buf, &len);
574:
575: /* 書き出した分をカウント */
576: ret += len;
577: remain -= len;
578:
579: if(0)printf("remain=[%d]\n", remain);
580: }
581:
582: return ret;
583: }
![]() | KAKU PROJECT (2009) |