2.2.x patch: http://people.apache.org/~sf/log_cookie_28037.diff
+1: sf, jim, rpluem
- * core: Pass the output filter information to newly created sub requests;
- as these are later on used as true requests with an internal redirect.
- This allows for mod_cache et.al. to trap the results of the redirect.
- Furthermore adjust the output filter chain correctly in an internal
- redirect from a subrequest, preserving filters from the main request as
- necessary.
- PR 17629, PR 43939
- Hint: Both PR need all revisions applied neither can be fixed by a subset
- of the revisions below.
- Trunk version of patch:
- http://svn.apache.org/viewcvs.cgi?rev=620133&view=rev
- http://svn.apache.org/viewcvs.cgi?rev=724515&view=rev
- http://svn.apache.org/viewcvs.cgi?rev=724805&view=rev
- http://svn.apache.org/viewcvs.cgi?rev=725077&view=rev
- http://svn.apache.org/viewcvs.cgi?rev=952828&view=rev
- Backport version for 2.2.x of patch:
- Trunk version of patch works
- For convenience (CHANGES might need some addition):
- http://people.apache.org/~rjung/patches/pr17629-2_2_x.patch
- +1: rpluem, jim, niq
-
PATCHES PROPOSED TO BACKPORT FROM TRUNK:
[ New proposals should be added at the end of the list ]
new->proto_output_filters = r->proto_output_filters;
new->proto_input_filters = r->proto_input_filters;
- new->output_filters = new->proto_output_filters;
new->input_filters = new->proto_input_filters;
if (new->main) {
- /* Add back the subrequest filter, which we lost when
- * we set output_filters to include only the protocol
- * output filters from the original request.
- */
- ap_add_output_filter_handle(ap_subreq_core_filter_handle,
- NULL, new, new->connection);
+ ap_filter_t *f, *nextf;
+
+ /* If this is a subrequest, the filter chain may contain a
+ * mixture of filters specific to the old request (r), and
+ * some inherited from r->main. Here, inherit that filter
+ * chain, and remove all those which are specific to the old
+ * request; ensuring the subreq filter is left in place. */
+ new->output_filters = r->output_filters;
+
+ f = new->output_filters;
+ do {
+ nextf = f->next;
+
+ if (f->r == r && f->frec != ap_subreq_core_filter_handle) {
+ ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r,
+ "dropping filter '%s' in internal redirect from %s to %s",
+ f->frec->name, r->unparsed_uri, new_uri);
+
+ /* To remove the filter, first set f->r to the *new*
+ * request_rec, so that ->output_filters on 'new' is
+ * changed (if necessary) when removing the filter. */
+ f->r = new;
+ ap_remove_output_filter(f);
+ }
+
+ f = nextf;
+
+ /* Stop at the protocol filters. If a protocol filter has
+ * been newly installed for this resource, better leave it
+ * in place, though it's probably a misconfiguration or
+ * filter bug to get into this state. */
+ } while (f && f != new->proto_output_filters);
+ }
+ else {
+ /* If this is not a subrequest, clear out all
+ * resource-specific filters. */
+ new->output_filters = new->proto_output_filters;
}
update_r_in_filters(new->input_filters, r, new);
r->output_filters = rr->output_filters;
r->input_filters = rr->input_filters;
- if (r->main) {
- ap_add_output_filter_handle(ap_subreq_core_filter_handle,
- NULL, r, r->connection);
- }
- else if (r->output_filters->frec == ap_subreq_core_filter_handle) {
- ap_remove_output_filter(r->output_filters);
- r->output_filters = r->output_filters->next;
- }
-
/* If any filters pointed at the now-defunct rr, we must point them
* at our "new" instance of r. In particular, some of rr's structures
* will now be bogus (say rr->headers_out). If a filter tried to modify
*/
update_r_in_filters(r->input_filters, rr, r);
update_r_in_filters(r->output_filters, rr, r);
+
+ if (r->main) {
+ ap_add_output_filter_handle(ap_subreq_core_filter_handle,
+ NULL, r, r->connection);
+ }
+ else {
+ /*
+ * We need to check if we now have the SUBREQ_CORE filter in our filter
+ * chain. If this is the case we need to remove it since we are NO
+ * subrequest. But we need to keep in mind that the SUBREQ_CORE filter
+ * does not necessarily need to be the first filter in our chain. So we
+ * need to go through the chain. But we only need to walk up the chain
+ * until the proto_output_filters as the SUBREQ_CORE filter is below the
+ * protocol filters.
+ */
+ ap_filter_t *next;
+
+ next = r->output_filters;
+ while (next && (next->frec != ap_subreq_core_filter_handle)
+ && (next != r->proto_output_filters)) {
+ next = next->next;
+ }
+ if (next && (next->frec == ap_subreq_core_filter_handle)) {
+ ap_remove_output_filter(next);
+ }
+ }
}
AP_DECLARE(void) ap_internal_redirect(const char *new_uri, request_rec *r)
/* Double check, we still don't multi-resolve non-ordinary files
*/
- if (sub_req->finfo.filetype != APR_REG)
+ if (sub_req->finfo.filetype != APR_REG) {
+ /* XXX sub req not destroyed -- may be a bug/unintentional ? */
continue;
+ }
/* If it has a handler, we'll pretend it's a CGI script,
* since that's a good indication of the sort of thing it
if (!variant->sub_req) {
int status;
- sub_req = ap_sub_req_lookup_file(variant->file_name, r, NULL);
+ sub_req = ap_sub_req_lookup_file(variant->file_name, r, r->output_filters);
status = sub_req->status;
if (status != HTTP_OK &&
* a sub_req structure yet. Get one now.
*/
- sub_req = ap_sub_req_lookup_file(best->file_name, r, NULL);
+ sub_req = ap_sub_req_lookup_file(best->file_name, r, r->output_filters);
if (sub_req->status != HTTP_OK) {
res = sub_req->status;
ap_destroy_sub_req(sub_req);