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