From: <php...@li...> - 2010-08-05 21:33:54
|
hi, *Problem* I noticed a difference the $_SERVER['REQUEST_URI'] in PHP between a native php environment and in Java Bridge. In my test, I have a /test/index.php with the following line: <?php echo $_SERVER['REQUEST_URI']?> When I run Java bridge in Jetty, and used index.php as a welcome file in web.xml, when I hit /test/, the REQUEST_URI is /test/index.php, i.e. included the index file name. But when run in Nginx, and used index.php as an index file, for an identical request to /test/, the REQUEST_URI is /test/, i.e. without the index file name. This difference in behavior caused a trouble when running Wordpress as it is too intelligent to try to redirect a link with /index.php to /, but after the redirection, the servlet-Java-Bridge environment tell the PHP the new request is from /index.php again and result as a dead loop. Other than the modifying wordpress' source code to disable its "canonical detection", I thought about a workaround to map the PHP CGI servlet to "/" (or /* or whatever without .php at the end). It doesn't work and even if it works, it will also map all static files like images or javascript files (and favicon.ico!) to PHP. *Solution* Traced the code, I notice JavaBridge is using the following code to obtain the request_uri in FastCGIServlet.java: env.requestUri = (String) req.getAttribute("javax.servlet.include.request_uri"); if (env.requestUri == null) env.requestUri = req.getRequestURI(); In my Jetty environment, req.getAttribute("javax.servlet.include.request_uri") returns null, however, req.getAttribute("javax.servlet.forward.request_uri") will return the correct uri before forwarding. (i.e. "/test/" instead of "/test/index.php") Both javax.servlet.include.request_uri and javax.servlet.forward.request_uri are defined in the Servlet spec. For include, in Servlet spec 8.3.1, it is stated that: > javax.servlet.include.request_uri > ... > These attributes are accessible from the included servlet via the > getAttribute method on the request object and their values must be equal to > the request URI, context path, servlet path, path info, and query string of > the included servlet, respectively. If the request is subsequently included, > these attributes are replaced for that include. > For forward, in Servlet spec 8.4.2, it is stated that: > javax.servlet.forward.request_uri > ... > The values of these attributes must be equal to the return values of the > HttpServletRequest methods getRequestURI, getContextPath, getServletPath, > getPathInfo, getQueryString respectively, invoked on the request object > passed to the *first servlet object* in the call chain that received the > request from the client. > I'm not sure which one is supposed to be correct but the javax.servlet.forward.request_uri attribute is said to be the request uri of the first servlet object of a chain, that won't be modified by subsequent servlet, and it gives a correct value in my test. could JavaBridge make a change either to use the forward.request_uri or just check both attributes? should i make a patch? regards, mingfai |
From: <php...@li...> - 2010-08-05 23:43:03
|
On Fri, Aug 6, 2010 at 5:33 AM, Mingfai <min...@gm...> wrote: > hi, > > *Problem* > I noticed a difference the $_SERVER['REQUEST_URI'] in PHP between a native > php environment and in Java Bridge. In my test, I have a /test/index.php > with the following line: > <?php echo $_SERVER['REQUEST_URI']?> > > > Other than REQUEST_URI, I notice HTTP_POST also caused a problem. The current JavaBridge set the HTTP_POST with: env.environment.put("HTTP_HOST", env.environment.get("SERVER_NAME") + ":" + env.environment.get("SERVER_PORT")); For port 80, it includes the port number. The actually variable is sth like acme.com:80 , but in Apache/Nginx, HTTP_HOST won't show the port number when the port is 80. Because Wordpress does url checking as a string, a slight different results in a redirection. e.g. when the first request is http://acme.com/index.php, wordpress' canonical.php redirect_canonical() will re-construct a request_url with schema ("http://" or https://") . HTTP_HOST . REQUEST_URI. The reconstructed url will becomes http://acme.com:80/index.php. As the reconstructed uri doesn't match the request url which is http://acme.com/index.php, it will make a redirect to the "correct" url without the port number. After redirected, JavaBridge appended the :80 again, and WP thinks it is wrong again and keep redirecting. For this case, I think JavaBridge should match the standard way to set variable like Apache and Nginx, i.e. not to include the port number for port 80 request. With both REQUEST_URI and HTTP_HOST fixed, I'm able to run Wordpress with JavaBridge. regards, mingfai |
From: <php...@li...> - 2010-08-06 09:10:15
|
> In my Jetty environment, > req.getAttribute("javax.servlet.include.request_uri") returns null, > however, req.getAttribute("javax.servlet.forward.request_uri") will return > the correct uri before forwarding Sounds like a jetty bug; if I remember correctly we don't need to check "javax.include.request_uri" attribute, because it is guaranteed to be the same as the return value of getRequestUri(). . > For port 80, it includes the port number. The actually variable is sth like > acme.com:80 , but in Apache/Nginx, HTTP_HOST won't show the port number when > the port is 80. Yes, this could be changed. However, java cannot listen on a privileged port anyway (as it cannot drop privileges), so I don't think the current behaviour is an issue. Can you please send me a patch? I will include it in version 6.2.1 Regards, Jost Bökemeier |
From: <php...@li...> - 2010-08-11 10:06:14
|
> if I remember correctly we don't need to > if I remember correctly we don't need to > check "javax.include.request_uri" attribute, because it is guaranteed > to be the same as the return value of getRequestUri() Above statement is false. javax.servlet.include points to the target and javax.servlet.forward to the source. We are interested in the target but not in the source; the current Java Bridge code is correct. <!-- from.jsp --> <jsp:include page="to.php"/> getXXXX() methods => from javax.servlet.include.xxx => to <!-- from.jsp --> <jsp:forward page="to.php"/> getXXXX() methods => to.php javax.servlet.forward.xxx => from If jetty returns null for request.getRequestURI(), please report this bug to the jetty maintainer. We cannot work around this jetty bug. > For port 80, it includes the port number. The actually variable is sth like > acme.com:80 , but in Apache/Nginx, HTTP_HOST won't show the port number when > the port is 80. Changed in CVS head. Thank you very much for sending the patch. Regards, Jost Bökemeier |
From: <php...@li...> - 2010-08-11 20:44:52
|
On Wed, Aug 11, 2010 at 6:05 PM, < php...@li...> wrote: > > if I remember correctly we don't need to > > if I remember correctly we don't need to > > check "javax.include.request_uri" attribute, because it is guaranteed > > to be the same as the return value of getRequestUri() > > Above statement is false. javax.servlet.include points to the target > and javax.servlet.forward to the source. We are interested in the > target but not in the source; the current Java Bridge code is correct. > For my scenario, taking the target but not the source caused problem. I'll explain as follows: > > <!-- from.jsp --> > <jsp:include page="to.php"/> > > getXXXX() methods => from > javax.servlet.include.xxx => to > > let me put the include case aside and look at the forward case only. > > <!-- from.jsp --> > <jsp:forward page="to.php"/> > > getXXXX() methods => to.php > javax.servlet.forward.xxx => from > Your example exactly match my understanding. If there are multiple from.jsp, e.g. from.jsp -> from2.jsp -> to.php, the javax.servlet.forward will include the first "from.jsp". The actual case is, user makes a request to "/", and jetty explicitly (not transparently) forward the request to "/index.php", and PJB uses the request at the time of "/index.php". When the page is forwarded to /index.php, the getRequestURI() correctly shows it is "/index.php". Jetty behaves correctly. For this scenario, JavaBridge should not use the to.php as REQUEST_URI, but should use the from. There is no problem in Tomcat because when we make a request to "/", it transparently take the index file "/index.php" but getRequestURI() remains at "/". But Jetty implements it differently and make the forwarding explicit. > If jetty returns null for request.getRequestURI(), please report this > bug to the jetty maintainer. We cannot work around this jetty bug. > as mentioned above, jetty correctly provides the requestURI value. it doesn't return null. I have to clarify it is not a Jetty bug and from understanding, Jetty behaves correctly. Now, come back to the question of whether Java Bridge should take the source or the target? it seems to me Java Bridge should always take the source as it is server side forwarding but not http redirect. When I try to get the REQUEST_URI in php, i expect to get the original request uri that the user make, which is the source but not the target. Is there any scenario Java Bridge will get problem if the source instead of target is taken? regards, mingfai |
From: <php...@li...> - 2010-08-12 07:45:34
|
> Your example exactly match my understanding. If there are multiple from.jsp, > e.g. from.jsp -> from2.jsp -> to.php, the javax.servlet.forward will include > the first "from.jsp". Yes. > When the page is forwarded to /index.php, the > getRequestURI() correctly shows it is "/index.php". The forwarding servlet should return "/" and the target servlet should return "/index.php" for getRequestURI(), yes. > Jetty behaves correctly. I don't follow. Doesn't jetty return null for getRequestURI()? > <!-- from.jsp --> > <jsp:forward page="to.php"/> ... > Now, come back to the question of whether Java Bridge should take the source > or the target? it seems to me Java Bridge should always take the source as > it is server side forwarding but not http redirect. How do you expect PHP to evaluate "from.jsp"? It should eval "to.php". > There is no problem in Tomcat because when we make a request to "/", it > transparently take the index file "/index.php" but getRequestURI() remains > at "/". In tomcat targetServlet.getRequestURI() returns "/index.php", as it should be. > For this scenario, JavaBridge should not use the to.php as REQUEST_URI, but > should use the from. If you know how to distinguish "this scenario", we can add a workaround for this jetty bug. Your current patch breaks code like <jsp:forward page="some.php">, so I will not apply it. Regards, Jost Bökemeier |
From: <php...@li...> - 2010-08-12 09:53:44
|
Hello! AFAIK this was a jetty bug and has been fixed. Jetty 7 correctly modifies the forwarded request, as required by the servlet spec. Peter |
From: <php...@li...> - 2010-08-12 10:59:59
|
> > Jetty behaves correctly. > > I don't follow. Doesn't jetty return null for getRequestURI()? > > sorry, maybe i didn't make it clear enough. Jetty does *not* return null for getRequestURI(). it "correctly" return "/index.php". There is no bug involved. I am using the latest Jetty 7.1.6 and it behaves exactly as I expected. Jetty may have bugs, maybe very buggy (if you guys think so, I don't really so ;-) ), but this issue doesn't caused by any Jetty bug. as you guys keep thinking it is a Jetty bug, I've checked the servlet spec by myself. the servlet spec 2.5 doesn't disallow explicit forwarding for welcome-file. In servlet spec 2.5 section 9.1, when a welcome file is defined, it only say "A request URI of /catalog/ will be returned as /catalog/default.jsp.". It used the term "returned" but not forwarded nor redirected. From the context, you actually may interpret "return" as "forward" because for the other case, the spec used the term "redirect".And the spec definitely didn't require getRequestURI to return the request uri of the first request. otherwise, it won't need the javax.servlet.forward.* attributes. the behavior of tomcat and jetty are different in welcome file implementation. Jetty actually explicitly do a forwarding, but tomcat doesn't do any forwarding (or it does the forwarding transparent). > > > <!-- from.jsp --> > > <jsp:forward page="to.php"/> > ... > > Now, come back to the question of whether Java Bridge should take the > source > > or the target? it seems to me Java Bridge should always take the source > as > > it is server side forwarding but not http redirect. > > How do you expect PHP to evaluate "from.jsp"? It should eval "to.php". > > Let's assume user type "http://acme.com/from.jsp". And in the jsp, it forwards to "/to.php". I do expect the REQUEST_URI variable in PHP shows "/from.jsp" which is the uri that the user requested. why?! this is a good question. the best reason i can give is "REQUEST_URI should return the URI that user requested" :-) - by fact, it won't work if REQUEST_URI isn't the original request uri in wordpress. As wordpress will do redirection if the uri is not correct. let's ignore wordpress first. it is popular but just one php applications. - in a normal web server like Apache or Nginx, if you view index file as a kind of servlet side forwarding, a request to "/test/" that is forwarded to "/test/index.php" will show "/test/" as the REQUEST_URI. "/test/" is the source, but not the forwarded target. - if you REQUEST_URI doesn't return the source, there is no way to obtain the source/original request uri. In PHP, we can use $_SERVER["SCRIPT_NAME"] to get the current file, which is the target. There is no need to make REQUEST_URI returns the same target. - i'm not a php expert. afaik, php doesn't have a server side forward feature, so there is no absolute expected behavior. it seems to me the definition of REQUEST_URI is a grey area so don't worry if our views are different. > > There is no problem in Tomcat because when we make a request to "/", it > > transparently take the index file "/index.php" but getRequestURI() > remains > > at "/". > > In tomcat targetServlet.getRequestURI() returns "/index.php", as it should > be. > > i did a test before writing my last email, and i just repeated the test to double check. In Tomcat 6.0.29, when the web app is configured with: <welcome-file-list> <welcome-file>index.jsp</welcome-file> </welcome-file-list> when we hit a URI without "index.jsp" suffix, e.g. "/test/", when there is actually a "/test/index.jsp" with the following content: <%=request.getRequestURI() %><br/> <%=request.getAttribute("javax.servlet.include.request_uri") %><br/> <%=request.getAttribute("javax.servlet.forward.request_uri") %><br/> it will print out: /test/ null null You could do a quick test with my attached test.war. The behavior of Tomcat is stated as a reference only. It got nothing to do with the issue I'm reporting. > > > For this scenario, JavaBridge should not use the to.php as REQUEST_URI, > but > > should use the from. > > If you know how to distinguish "this scenario", we can add a > workaround for this jetty bug. Your current patch breaks code like > <jsp:forward page="some.php">, so I will not apply it. > I think the issue is not a workaround, and as mentioned, Jetty behaves correctly. The issue is our difference in the expected behavior of a jsp forward case. I think the REQUEST_URI should return the source but not the target, and you think differently. btw, Tomcat doesn't implemenet javax.servlet.* attributes at all so the patch won't affect it. I Even thought I want to fix "this scenario", i wouldn't suggest to detect if it is jetty and then sth differently for Jetty. right now, i've patched my local version. Not the best but acceptable to me. And I think FastCGIServlet is designed to be extendable so anyone could override the setupRequestVariables method. If you don't REQUEST_URI should return the source, just ignore this issue. Don't worry. regards, mingfai |
From: <php...@li...> - 2010-08-12 12:01:14
|
> it seems to me the definition of REQUEST_URI is a grey area so don't worry > if our views are different. From => http://www.php.net/manual/en/reserved.variables.server.php 'REQUEST_URI' The URI which was given in order to access this page; for instance, '/index.html'. ... But from the comments below: danny at orionrobots dot co dot uk 31-Jul-2008 09:25 It is worth noting here that if you use $_SERVER['REQUEST_URI'] with a rewrite rule, the original, not rewritten URI will be presented. I have changed your ticket state back to open. Regards, Jost Bökemeier |
From: <php...@li...> - 2010-08-12 18:34:35
|
On Thu, Aug 12, 2010 at 8:01 PM, < php...@li...> wrote: > > it seems to me the definition of REQUEST_URI is a grey area so don't > worry > > if our views are different. > > From > > => http://www.php.net/manual/en/reserved.variables.server.php > > 'REQUEST_URI' > The URI which was given in order to access this page; for > instance, '/index.html'. > > ... > > But from the comments below: > > danny at orionrobots dot co dot uk > 31-Jul-2008 09:25 > It is worth noting here that if you use $_SERVER['REQUEST_URI'] with a > rewrite rule, the original, not rewritten URI will be presented. > > > I have changed your ticket state back to open. > > > Thank you. If you treat Servlet forwarding as same as URL rewrite, then we should use the source. > btw, Tomcat doesn't implemenet javax.servlet.* attributes at all so the > patch won't affect it. I My previous comment was wrong. It is true only for the welcome file case. If there is an actual servlet side forward, Tomcat does implement the javax.servlet.forward.request_uri attribute. And my patch will change the behavior. To me, it is a fix. btw, sorry for the lack of proofreading of my previous email. It was sent in a rush. :-P regards, mingfai |
From: <php...@li...> - 2010-08-13 12:09:04
|
Fixed in CVS head. >From the NEWS file: * Incompatible change for those who use $_SERVER["REQUEST_URI"] as a cache key. Please either use PHP_SELF or please set <init-param> <param-name>php_request_uri_is_unique</param-name> <param-value>true</param-value> </init-param> |