diff options
Diffstat (limited to 'ext/kcar/kcar.rl')
-rw-r--r-- | ext/kcar/kcar.rl | 41 |
1 files changed, 38 insertions, 3 deletions
diff --git a/ext/kcar/kcar.rl b/ext/kcar/kcar.rl index ea3dacc..6330910 100644 --- a/ext/kcar/kcar.rl +++ b/ext/kcar/kcar.rl @@ -201,6 +201,13 @@ static void finalize_header(struct http_parser *hp, VALUE hdr) if (hp->has_trailer && !hp->chunked) rb_raise(eParserError, "trailer but not chunked"); if (hp->is_request) { + if (hp->chunked) { + if (hp->len.chunk >= 0) + rb_raise(eParserError, "Content-Length set with chunked encoding"); + else + hp->len.chunk = 0; + } + if (!hp->has_query) rb_hash_aset(hdr, g_QUERY_STRING, rb_str_new(NULL, 0)); if (hp->has_header) { @@ -831,6 +838,8 @@ static VALUE body_bytes_left_set(VALUE self, VALUE bytes) if (hp->chunked) rb_raise(rb_eRuntimeError, "body_bytes_left= is not for chunked bodies"); hp->len.content = NUM2OFFT(bytes); + if (hp->len.content == 0) + hp->body_eof_seen = 1; return bytes; } @@ -973,8 +982,12 @@ static VALUE keepalive(VALUE self) if (hp->persistent) { if (hp->has_header && hp->has_body) { - if (hp->chunked || (hp->len.content >= 0)) - return Qtrue; + if (hp->chunked || (hp->len.content >= 0)) { + if (!hp->is_request) + return Qtrue; + else + return hp->body_eof_seen ? Qtrue : Qfalse; + } /* unknown Content-Length and not chunked, we must assume close */ return Qfalse; @@ -1012,12 +1025,34 @@ static VALUE filter_body(VALUE self, VALUE dst, VALUE src) StringValue(dst); rb_str_modify(dst); - rb_str_resize(dst, slen); /* we can never copy more than slen bytes */ OBJ_TAINT(dst); /* keep weirdo $SAFE users happy */ + /* + * for now, only support filter_body for identity requests, + * not responses; it's rather inefficient to blindly memcpy + * giant request bodies; on the other hand, it simplifies + * server-side code. + */ + if (hp->is_request && !hp->chunked) { + /* no need to enter the Ragel machine for unchunked transfers */ + assert(hp->len.content >= 0 && "negative Content-Length"); + if (hp->len.content > 0) { + long nr = MIN(slen, hp->len.content); + + rb_str_resize(dst, nr); + memcpy(RSTRING_PTR(dst), sptr, nr); + hp->len.content -= nr; + if (hp->len.content == 0) + hp->body_eof_seen = 1; + advance_str(src, nr); + } + return dst; + } + if (!hp->chunked) rb_raise(rb_eRuntimeError, "filter_body is only for chunked bodies"); + rb_str_resize(dst, slen); /* we can never copy more than slen bytes */ if (!chunked_eof(hp)) { hp->s.dest_offset = 0; http_parser_execute(hp, dst, sptr, slen); |