Return-Path: X-Original-To: apmail-tomcat-users-archive@www.apache.org Delivered-To: apmail-tomcat-users-archive@www.apache.org Received: from mail.apache.org (hermes.apache.org [140.211.11.3]) by minotaur.apache.org (Postfix) with SMTP id 51F841885E for ; Mon, 5 Oct 2015 02:21:47 +0000 (UTC) Received: (qmail 6930 invoked by uid 500); 5 Oct 2015 02:21:44 -0000 Delivered-To: apmail-tomcat-users-archive@tomcat.apache.org Received: (qmail 6871 invoked by uid 500); 5 Oct 2015 02:21:44 -0000 Mailing-List: contact users-help@tomcat.apache.org; run by ezmlm Precedence: bulk List-Help: List-Unsubscribe: List-Post: List-Id: Reply-To: "Tomcat Users List" Delivered-To: mailing list users@tomcat.apache.org Received: (qmail 6860 invoked by uid 99); 5 Oct 2015 02:21:44 -0000 Received: from Unknown (HELO spamd1-us-west.apache.org) (209.188.14.142) by apache.org (qpsmtpd/0.29) with ESMTP; Mon, 05 Oct 2015 02:21:44 +0000 Received: from localhost (localhost [127.0.0.1]) by spamd1-us-west.apache.org (ASF Mail Server at spamd1-us-west.apache.org) with ESMTP id DA35AC25BB for ; Mon, 5 Oct 2015 02:21:43 +0000 (UTC) X-Virus-Scanned: Debian amavisd-new at spamd1-us-west.apache.org X-Spam-Flag: NO X-Spam-Score: 2.899 X-Spam-Level: ** X-Spam-Status: No, score=2.899 tagged_above=-999 required=6.31 tests=[DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, HTML_MESSAGE=3, RCVD_IN_MSPIKE_H2=-0.001, SPF_PASS=-0.001, URIBL_BLOCKED=0.001] autolearn=disabled Authentication-Results: spamd1-us-west.apache.org (amavisd-new); dkim=pass (2048-bit key) header.d=gmail.com Received: from mx1-eu-west.apache.org ([10.40.0.8]) by localhost (spamd1-us-west.apache.org [10.40.0.7]) (amavisd-new, port 10024) with ESMTP id gX_8Pz4DEtaw for ; Mon, 5 Oct 2015 02:21:38 +0000 (UTC) Received: from mail-io0-f179.google.com (mail-io0-f179.google.com [209.85.223.179]) by mx1-eu-west.apache.org (ASF Mail Server at mx1-eu-west.apache.org) with ESMTPS id 27AD3203A3 for ; Mon, 5 Oct 2015 02:21:37 +0000 (UTC) Received: by ioiz6 with SMTP id z6so171029781ioi.2 for ; Sun, 04 Oct 2015 19:21:36 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20120113; h=mime-version:in-reply-to:references:date:message-id:subject:from:to :content-type; bh=C94w0OtgLvKzdKfY2VMNKNT2C0GnDdv4fjSK2NL69ic=; b=qyhLTzhPpSJavUGYo4IQRkG9Q0h1snrak1oQwd5NgbCwfd07ygwGXMsNH3ss4RgeUG sK7Lnc0aQWViKrIaJggJHMn/yc5LATKQHzWxJlT7WDwgRih5FzU+6jomE5wD8vSxYAr1 Yt/VqiTB3F7N/xCVVxwn3HTUc0y8c5+IzXeYDLAOn6Br39hV4l9WqDaJECEPfdlpKg2y B5115EkUFRwCaAQT0eVjb5ZAUYZIdGkyAniopuclm9y57sAwkybOq1lWASjP5JJukxtW R5XOMwWD4LTjiufZfP9ZORXb+IS7LlRlM8zlGS22pBO6X8JLYGV72ndcW415tWtXZPUp KW7Q== MIME-Version: 1.0 X-Received: by 10.107.41.138 with SMTP id p132mr25236106iop.188.1444011695939; Sun, 04 Oct 2015 19:21:35 -0700 (PDT) Received: by 10.36.123.194 with HTTP; Sun, 4 Oct 2015 19:21:35 -0700 (PDT) In-Reply-To: References: Date: Sun, 4 Oct 2015 22:21:35 -0400 Message-ID: Subject: Re: Rewriting entire request /body in Servlet Filter not working as expected From: Michael Greco To: users@tomcat.apache.org Content-Type: multipart/alternative; boundary=001a1141f15a3028fc0521522cf7 --001a1141f15a3028fc0521522cf7 Content-Type: text/plain; charset=UTF-8 On Sun, Oct 4, 2015 at 7:25 PM, Michael Greco wrote: > On Sun, Oct 4, 2015 at 2:03 PM, Michael Greco > wrote: > >> First time post here. >> >> Using : >> Tomcat 8.0.26 >> JDK1.8.0 update 51 >> Apache MyFaces 2.2.8. >> Maven build of webapp war file >> Chrome 45.0.2454.101 m 64 bit >> Windows 7 64 bit >> >> Trying to rewrite the entire request body in a filter using a http >> request wrapper. Not entirely sure if this is the right approach or even >> possible but researching similar examples it seems this approach should >> work. Created a simple test case with a one page test app, expecting the >> index.xhtml page's text value of "Welcome" to be replaced with the text >> "NEW TEXT HERE" found in the filter code, but I only get "Welcome" back >> when the page is rendered in the browser. >> >> Below is what I have in the index page, the filter and the web.xml and >> the pom.xml. The reason I can see is that the getInputStream() or >> getReader() calls are never called by the FacesServlet in the extended >> HttpServletRequestWrapper. I did override the getParameter function to put >> some simple debug output in there to ensure the wrapped request was >> actually used, so I know it's definitely getting into this class but not >> calling the methods that would return it the new body content. >> >> I even tried to re-read the entire request in the getParametersMap() from >> examples I found on the web, but this didn't seen to do the job either. It >> seems that the request body is somehow cached somewhere / somehow and not >> changable? >> >> Thanks in advance for any insight on this. >> >> index page code (index.xhtml) : >> >> --------------------------------------------------------------------------------- >> >> > xmlns="http://www.w3.org/1999/xhtml" >> xmlns:jsf="http://xmlns.jcp.org/jsf" >> xmlns:h="http://xmlns.jcp.org/jsf/html"> >> >> >> Test Webapp >> >> >>

Welcome

>> >> >> >> Filter code : >> -------------------------------------------------------------------------- >> package com.testwebapp.reqrewrite.filter; >> >> import java.io.BufferedReader; >> import java.io.ByteArrayInputStream; >> import java.io.IOException; >> import java.io.InputStreamReader; >> >> import javax.servlet.Filter; >> import javax.servlet.FilterChain; >> import javax.servlet.FilterConfig; >> import javax.servlet.ReadListener; >> import javax.servlet.ServletException; >> import javax.servlet.ServletInputStream; >> import javax.servlet.ServletRequest; >> import javax.servlet.ServletResponse; >> import javax.servlet.http.HttpServletRequest; >> import javax.servlet.http.HttpServletRequestWrapper; >> >> public class RewriteBodyTestFilter implements Filter { >> >> public void init(FilterConfig filterConfig) throws ServletException { >> return; >> } >> >> public void doFilter(ServletRequest request, ServletResponse response, >> FilterChain chain) >> throws IOException, ServletException { >> String newReqBody = new String("

NEW TEXT HERE

"); >> HttpServletRequest req = (HttpServletRequest)request; >> RewriteBodyRequestWrapper rewriteBodyRequestWrapper = new >> RewriteBodyRequestWrapper(req, newReqBody); >> chain.doFilter(rewriteBodyRequestWrapper, response); >> } >> >> public void destroy() { >> return; >> } >> class RewriteBodyRequestWrapper extends HttpServletRequestWrapper { >> >> private byte[] buffer; >> >> public RewriteBodyRequestWrapper(HttpServletRequest req, String reqBody) >> throws IOException { >> super(req); >> System.out.println("entering RewriteBodyRequestWrapper() constructor"); >> this.buffer = reqBody.getBytes(); >> } >> >> @Override >> public ServletInputStream getInputStream() { >> System.out.println("entering >> RewriteBodyRequestWrapper().getInputStream()"); >> try { >> ByteArrayInputStream bais = new ByteArrayInputStream(buffer); >> BufferedServletInputStream bsis = new BufferedServletInputStream(bais); >> return bsis; >> } catch (Exception ex) { >> ex.printStackTrace(); >> throw new RuntimeException(ex); >> } >> } >> >> @Override >> public BufferedReader getReader() { >> System.out.println("entering RewriteBodyRequestWrapper().getReader()"); >> InputStreamReader isr = new InputStreamReader(getInputStream()); >> return new BufferedReader(isr); >> } >> >> } >> class BufferedServletInputStream extends ServletInputStream { >> >> ByteArrayInputStream bais; >> >> public BufferedServletInputStream(ByteArrayInputStream bais) { >> this.bais = bais; >> } >> >> @Override >> public int available() { >> return bais.available(); >> } >> >> @Override >> public boolean isFinished() { >> return bais.available() == 0; >> } >> >> @Override >> public boolean isReady() { >> return true; >> } >> >> @Override >> public void setReadListener(ReadListener readListener) { >> return; >> } >> >> @Override >> public int read() { >> return bais.read(); >> } >> >> @Override >> public int read(byte[] buf) { >> return this.read(buf, 0, buf.length); >> } >> >> @Override >> public int read(byte[] buf, int off, int len) { >> return bais.read(buf, off, len); >> } >> >> } >> } >> >> web.xml code: >> >> -------------------------------------------------------------------------------------------------- >> >> > xsi:schemaLocation="http://java.sun.com/xml/ns/javaee >> http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" >> metadata-complete="true" version="3.0"> >> >> Test Webapp Req Rewrite >> >> >> >> javax.faces.PROJECT_STAGE >> Development >> >> >> >> >> FacesServlet >> javax.faces.webapp.FacesServlet >> 1 >> >> >> >> >> FacesServlet >> /faces/* >> >> >> >> >> 30 >> >> >> >> >> faces/index.xhtml >> >> >> >> >> RewriteBodyTestFilter >> com.testwebapp.reqrewrite.filter.RewriteBodyTestFilter >> >> >> >> >> >> RewriteBodyTestFilter >> FacesServlet >> REQUEST >> FORWARD >> >> >> >> >> pom.xml : >> >> ------------------------------------------------------------------------------------- >> > xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 >> http://maven.apache.org/maven-v4_0_0.xsd"> >> 4.0.0 >> com.testwebapp.reqrewrite >> reqrewrite >> war >> 1.0-SNAPSHOT >> reqrewrite Maven Webapp >> http://maven.apache.org >> >> >> javax.servlet >> javax.servlet-api >> 3.1.0 >> provided >> >> >> org.apache.myfaces.core >> myfaces-api >> 2.2.8 >> >> >> org.apache.myfaces.core >> myfaces-impl >> 2.2.8 >> >> >> >> reqrewrite >> >> >> >> >> I think I might know what is going on now. A specific > HttpServletRequestWrapper superclass method is being invoked first > (something other than getInputStream() and getReader()) and my overridden > methods getInputStream() and getReader() of my subclass are not being > invoked because of this, which leaves me to having to figure out this first > method invoked in the FacesServlet execution path that later invokes > getInputStream() and getReader() and then override this as well? I really > think it would be a bad idea for me to try to implement/override more of > the container's request object methods beyond what I've done already. Is > there another design pattern here that I can utilize to get around this > issue? I would assume this issue probably varies from container to > container depending on how the server implements the seeded request classes. > (Sorry for the Top Post, and not sure if this next identical response will > be Bottom Post until I try, using Gmail web client) > > Thanks > Mike > Looking into the Tomcat 8.0.26 Javadocs and using a bit of reflection I see I'm dealing with the following classes. I was going to try a hack and use reflection to reset the input stream, but then I thought otherwise cause I'm sure that's probably just plain wrong. I'm stumped on this one, it seems folks have modified the "body" but I'm thinking they could have only done this on the response back up the chain. There appears to be no way to do this, to modify the request body, from what I can see, going down the chain to the servlet. // org.apache.catalina.connector.RequestFacade // org.apache.catalina.connector.Request // org.apache.catalina.connector.CoyoteInputStream // org.apache.catalina.connector.InputBuffer // org.apache.coyote.Request (accessed by attribute org.apache.tomcat.request by trusted apps) --001a1141f15a3028fc0521522cf7--