stas 2003/11/06 03:22:03
Modified: src/modules/perl modperl_io_apache.c modperl_io_apache.h xs/Apache/RequestIO Apache__RequestIO.h xs/maps modperl_functions.map xs/tables/current/ModPerl FunctionTable.pm . Changes Log: rewrite $r->read() and perlio read functions to use the same function, which completely satisfies the read request if possible, on the way getting rid of get_client_block and its supporting functions which have problems and will most likely will be removed from the httpd-API in the future. Directly manipulate bucket brigades instead. Revision Changes Path 1.9 +81 -24 modperl-2.0/src/modules/perl/modperl_io_apache.c Index: modperl_io_apache.c =================================================================== RCS file: /home/cvs/modperl-2.0/src/modules/perl/modperl_io_apache.c,v retrieving revision 1.8 retrieving revision 1.9 diff -u -u -r1.8 -r1.9 --- modperl_io_apache.c 1 Nov 2003 09:25:02 -0000 1.8 +++ modperl_io_apache.c 6 Nov 2003 11:22:02 -0000 1.9 @@ -105,37 +105,17 @@ PerlIOApache *st = PerlIOSelf(f, PerlIOApache); request_rec *r = st->r; long total = 0; - int rc; if (!(PerlIOBase(f)->flags & PERLIO_F_CANREAD) || PerlIOBase(f)->flags & (PERLIO_F_EOF|PERLIO_F_ERROR)) { return 0; } - if (!r->read_length) { - /* only do this once per-request */ - if ((rc = ap_setup_client_block(r, REQUEST_CHUNKED_ERROR)) != OK) { - ap_log_error(APLOG_MARK, APLOG_ERR, 0, r->server, - "mod_perl: ap_setup_client_block failed: %d", rc); - return -1; - } - } - - if (r->read_length || ap_should_client_block(r)) { - total = ap_get_client_block(r, vbuf, count); + total = modperl_request_read(aTHX_ r, (char*)vbuf, count); - MP_TRACE_o(MP_FUNC, "wanted %db, read %db [%s]", - count, total, - IO_DUMP_FIRST_CHUNK(r->pool, vbuf, total)); - - if (total < 0) { - /* - * XXX: as stated in ap_get_client_block, the real - * error gets lots, so we only know that there was one - */ - ap_log_error(APLOG_MARK, APLOG_ERR, 0, r->server, - "mod_perl: $r->read failed to read"); - } + if (total < 0) { + PerlIOBase(f)->flags |= PERLIO_F_ERROR; + /* modperl_request_read takes care of setting ERRSV */ } return total; @@ -268,6 +248,83 @@ #endif /* defined MP_IO_TIE_PERLIO */ +/****** Other request IO functions *******/ + + +MP_INLINE SSize_t modperl_request_read(pTHX_ request_rec *r, + char *buffer, Size_t len) +{ + long total = 0; + int wanted = len; + int seen_eos = 0; + char *tmp = buffer; + apr_bucket_brigade *bb; + + if (len <= 0) { + return 0; + } + + bb = apr_brigade_create(r->pool, r->connection->bucket_alloc); + if (bb == NULL) { + r->connection->keepalive = AP_CONN_CLOSE; + return -1; + } + + do { + apr_size_t read; + int rc; + + rc = ap_get_brigade(r->input_filters, bb, AP_MODE_READBYTES, + APR_BLOCK_READ, len); + if (rc != APR_SUCCESS) { + /* if we fail here, we want to just return and stop trying + * to read data from the client. + */ + r->connection->keepalive = AP_CONN_CLOSE; + apr_brigade_destroy(bb); + sv_setpv(ERRSV, + (char *)apr_psprintf(r->pool, + "failed to get bucket brigade: %s", + modperl_apr_strerror(rc))); + return -1; + } + + /* If this fails, it means that a filter is written + * incorrectly and that it needs to learn how to properly + * handle APR_BLOCK_READ requests by returning data when + * requested. + */ + AP_DEBUG_ASSERT(!APR_BRIGADE_EMPTY(bb)); + + if (APR_BUCKET_IS_EOS(APR_BRIGADE_LAST(bb))) { + seen_eos = 1; + } + + read = len; + rc = apr_brigade_flatten(bb, tmp, &read); + if (rc != APR_SUCCESS) { + apr_brigade_destroy(bb); + sv_setpv(ERRSV, + (char *)apr_psprintf(r->pool, + "failed to read: %s", + modperl_apr_strerror(rc))); + return -1; + } + total += read; + tmp += read; + len -= read; + + apr_brigade_cleanup(bb); + + } while (len > 0 && !seen_eos); + + apr_brigade_destroy(bb); + + MP_TRACE_o(MP_FUNC, "wanted %db, read %db [%s]", wanted, total, + IO_DUMP_FIRST_CHUNK(r->pool, buffer, total)); + + return total; +} 1.2 +4 -1 modperl-2.0/src/modules/perl/modperl_io_apache.h Index: modperl_io_apache.h =================================================================== RCS file: /home/cvs/modperl-2.0/src/modules/perl/modperl_io_apache.h,v retrieving revision 1.1 retrieving revision 1.2 diff -u -u -r1.1 -r1.2 --- modperl_io_apache.h 20 Aug 2003 23:20:14 -0000 1.1 +++ modperl_io_apache.h 6 Nov 2003 11:22:02 -0000 1.2 @@ -25,5 +25,8 @@ #define modperl_io_apache_init(pTHX) #endif /* #ifdef PERLIO_LAYERS */ - + +MP_INLINE SSize_t modperl_request_read(pTHX_ request_rec *r, + char *buffer, Size_t len); + #endif /* MODPERL_IO_APACHE_H */ 1.39 +25 -35 modperl-2.0/xs/Apache/RequestIO/Apache__RequestIO.h Index: Apache__RequestIO.h =================================================================== RCS file: /home/cvs/modperl-2.0/xs/Apache/RequestIO/Apache__RequestIO.h,v retrieving revision 1.38 retrieving revision 1.39 diff -u -u -r1.38 -r1.39 --- Apache__RequestIO.h 20 Aug 2003 23:13:28 -0000 1.38 +++ Apache__RequestIO.h 6 Nov 2003 11:22:02 -0000 1.39 @@ -206,55 +206,45 @@ (r->read_length || ap_should_client_block(r)) /* alias */ -#define mpxs_Apache__RequestRec_READ(r, buffer, bufsiz, offset) \ - mpxs_Apache__RequestRec_read(aTHX_ r, buffer, bufsiz, offset) +#define mpxs_Apache__RequestRec_READ(r, bufsv, len, offset) \ + mpxs_Apache__RequestRec_read(aTHX_ r, bufsv, len, offset) static long mpxs_Apache__RequestRec_read(pTHX_ request_rec *r, - SV *buffer, int bufsiz, + SV *bufsv, int len, int offset) { - long total = 0; - int rc; + long total; - if ((rc = mpxs_setup_client_block(r)) != APR_SUCCESS) { - return 0; + if (!SvOK(bufsv)) { + sv_setpvn(bufsv, "", 0); } - if (mpxs_should_client_block(r)) { - long nrd; - /* ap_should_client_block() will return 0 if r->read_length */ - mpxs_sv_grow(buffer, bufsiz+offset); - while (bufsiz) { - nrd = ap_get_client_block(r, SvPVX(buffer)+offset+total, bufsiz); - if (nrd > 0) { - total += nrd; - bufsiz -= nrd; - } - else if (nrd == 0) { - break; - } - else { - /* - * XXX: as stated in ap_get_client_block, the real - * error gets lots, so we only know that there was one - */ - ap_log_error(APLOG_MARK, APLOG_ERR, 0, r->server, - "mod_perl: $r->read failed to read"); - break; - } - } + if (len <= 0) { + return 0; } + /* XXX: need to handle negative offset */ + /* XXX: need to pad with \0 if offset > size of the buffer */ + + mpxs_sv_grow(bufsv, len+offset); + total = modperl_request_read(aTHX_ r, SvPVX(bufsv)+offset, len); + if (total > 0) { - mpxs_sv_cur_set(buffer, offset+total); - SvTAINTED_on(buffer); + mpxs_sv_cur_set(bufsv, offset+total); + SvTAINTED_on(bufsv); } + else if (total == 0) { + sv_setpvn(bufsv, "", 0); + } else { - sv_setpvn(buffer, "", 0); + /* need to return undef according to the read entry, but at + * the moment we return IV, so need to change to return SV, + * meanwhile just crock */ + if (SvTRUE(ERRSV)) { + (void)modperl_errsv(aTHX_ HTTP_INTERNAL_SERVER_ERROR, r, NULL); + } } - MP_TRACE_o(MP_FUNC, "%d bytes [%s]", total, SvPVX(buffer)); - return total; } 1.59 +2 -2 modperl-2.0/xs/maps/modperl_functions.map Index: modperl_functions.map =================================================================== RCS file: /home/cvs/modperl-2.0/xs/maps/modperl_functions.map,v retrieving revision 1.58 retrieving revision 1.59 diff -u -u -r1.58 -r1.59 --- modperl_functions.map 30 Aug 2003 02:33:26 -0000 1.58 +++ modperl_functions.map 6 Nov 2003 11:22:02 -0000 1.59 @@ -46,8 +46,8 @@ SV *:DEFINE_CLOSE | | request_rec *:r SV *:DEFINE_UNTIE | | request_rec *:r, int:refcnt mpxs_Apache__RequestRec_sendfile | | r, filename=r->filename, offset=0, len=0 - mpxs_Apache__RequestRec_read | | r, buffer, bufsiz, offset=0 - long:DEFINE_READ | | request_rec *:r, SV *:buffer, int:bufsiz, int:offset=0 + mpxs_Apache__RequestRec_read | | r, bufsv, len, offset=0 + long:DEFINE_READ | | request_rec *:r, SV *:bufsv, int:len, int:offset=0 mpxs_Apache__RequestRec_write | | r, buffer, bufsiz=-1, offset=0 mpxs_Apache__RequestRec_print | | ... apr_ssize_t:DEFINE_WRITE | | \ 1.127 +27 -2 modperl-2.0/xs/tables/current/ModPerl/FunctionTable.pm Index: FunctionTable.pm =================================================================== RCS file: /home/cvs/modperl-2.0/xs/tables/current/ModPerl/FunctionTable.pm,v retrieving revision 1.126 retrieving revision 1.127 diff -u -u -r1.126 -r1.127 --- FunctionTable.pm 14 Oct 2003 17:32:40 -0000 1.126 +++ FunctionTable.pm 6 Nov 2003 11:22:02 -0000 1.127 @@ -5754,16 +5754,41 @@ }, { 'type' => 'SV *', - 'name' => 'buffer' + 'name' => 'bufsv' }, { 'type' => 'int', - 'name' => 'bufsiz' + 'name' => 'len' }, { 'type' => 'int', 'name' => 'offset' } + ] + }, + { + 'return_type' => 'SSize_t', + 'name' => 'modperl_request_read', + 'attr' => [ + 'static' + ], + 'args' => [ + { + 'type' => 'PerlInterpreter *', + 'name' => 'my_perl' + }, + { + 'type' => 'request_rec *', + 'name' => 'r' + }, + { + 'type' => 'char *', + 'name' => 'buffer' + }, + { + 'type' => 'Size_t', + 'name' => 'len' + }, ] }, { 1.246 +6 -0 modperl-2.0/Changes Index: Changes =================================================================== RCS file: /home/cvs/modperl-2.0/Changes,v retrieving revision 1.245 retrieving revision 1.246 diff -u -u -r1.245 -r1.246 --- Changes 5 Nov 2003 19:36:15 -0000 1.245 +++ Changes 6 Nov 2003 11:22:02 -0000 1.246 @@ -12,6 +12,12 @@ =item 1.99_11-dev - +rewrite $r->read() and perlio read functions to use the same function, +which completely satisfies the read request if possible, on the way +getting rid of get_client_block and its supporting functions which +have problems and will most likely will be removed from the httpd-API +in the future. Directly manipulate bucket brigades instead. [Stas] + Since Apache2.pm pops /foo/Apache2 dirs to the top of @INC, it now also takes care of keeping lib and blib dirs before the system dirs, so that previously installed libraries won't get loaded instead of the