tomee-users mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From Chet Hosey <ChetHo...@gmail.com>
Subject Re: UriInfo always returning "localhost" in URIs
Date Thu, 07 Feb 2013 14:05:35 GMT
AJP isn't generally exposed to the client at all.

A typical configuration might include a web server such httpd or IIS listening on a public
IP on port 80, and several Tomcat instances running AJP on private IP addresses. The web server
is configured to route certain requests (like /appname/*) to a running Tomcat instance via
AJP. If sessions are clustered, or the conversations are stateless, an administrator shut
down an individual Tomcat instance without impacting external users.

So a REST request would be made over HTTP (or HTTPS) to the web server, and routed to one
of the Tomcat instances over AJP. There's nothing special about REST that makes AJP inappropriate;
it's just a way of connecting a web server to Tomcat. But please consider an HTTP load balancer
running on port 80, and sending requests to internal Tomcat instances running on ports 8080,
8081, etc. The client will send requests to port 80. But none of Tomcat servers' connectors
will be bound to the same port. It would similar to AJP, in that the public port doesn't match
the Tomcat connectors' listen ports. And all communication would be over HTTP.

Even with requests over AJP, for example, a REST method can get an injected HttpServletRequest
object. My test code demonstrates that. This is why I believe that the right behavior for
UriInfo would be to match the behavior of the HttpServletRequest object. It generally works
out-of-the-box, and there are already ways for an administrator to override the values returned
by HttpServletRequest without having to alter the application.

I'll try the latest snapshot, and put the AJP connector first as you advise. Please consider,
though, that the correct public host / port may never match a connector's configuration, and
that it may be better for UriInfo to get these values from an HttpServletRequest than to check
the connectors.

Thanks!

On Feb 7, 2013, at 8:14 AM, Romain Manni-Bucau <rmannibucau@gmail.com> wrote:

> updated as possible as it was this feature
> 
> can you try with the next snapshot please?
> 
> where i doubt is when using ajp protocol you don't really respect REST
> specification which relies on http only.
> 
> *Romain Manni-Bucau*
> *Twitter: @rmannibucau <https://twitter.com/rmannibucau>*
> *Blog: **http://rmannibucau.wordpress.com/*<http://rmannibucau.wordpress.com/>
> *LinkedIn: **http://fr.linkedin.com/in/rmannibucau*
> *Github: https://github.com/rmannibucau*
> 
> 
> 
> 2013/2/7 Romain Manni-Bucau <rmannibucau@gmail.com>
> 
>> Hmm, the point is it needs to select the connector to use for deployment
>> (to compute the base address)...not sure of a clever way here
>> 
>> Can you try to define ajp connector first in server.xml please?
>> Le 7 févr. 2013 08:24, "Chet Hosey" <gargantuchet@gmail.com> a écrit :
>> 
>> To say that it's "deployed on HTTP" is inaccurate. It's deployed on
>>> Tomcat, which TomEE is built around, and which provides more than one type
>>> of connector.
>>> 
>>> It's common to use httpd in front of Tomcat to serve static content,
>>> balance between multiple workers, etc. It's reasonable that AJP support
>>> might not be ready yet or might have been overlooked.
>>> 
>>> The statements on the project's website suggest that the goal is to add
>>> features to Tomcat without sacrificing functionality:
>>> 
>>> - Goal: "Simple, Get more from Tomcat without giving anything up."
>>> - Focuses: "Don't mess with Tomcat"
>>> - TomEE doesn't "include Tomcat in some truncated and stripped-down form"
>>> - With TomEE, there's "no picking and choosing individual parts of Tomcat
>>> and building a 'new' server leveraging Tomcat."
>>> 
>>> With such strong language, it would be surprising if the project didn't
>>> plan to support AJP connections as it does HTTP.
>>> 
>>> Might this be addressed in a future release? Can you suggest ways to
>>> contribute?
>>> 
>>> 
>>> On Feb 6, 2013, at 5:40 PM, Romain Manni-Bucau <rmannibucau@gmail.com>
>>> wrote:
>>> 
>>>> because the REST service is deployed on HTTP not AJP
>>>> 
>>>> *Romain Manni-Bucau*
>>>> *Twitter: @rmannibucau <https://twitter.com/rmannibucau>*
>>>> *Blog: **http://rmannibucau.wordpress.com/*<
>>> http://rmannibucau.wordpress.com/>
>>>> *LinkedIn: **http://fr.linkedin.com/in/rmannibucau*
>>>> *Github: https://github.com/rmannibucau*
>>>> 
>>>> 
>>>> 
>>>> 2013/2/6 Chet Hosey <ChetHosey@gmail.com>
>>>> 
>>>>> 
>>>>> That was my expectation too. But it just isn't working that way for me
>>>>> with AJP.
>>>>> 
>>>>> Apache httpd is listening on port 8888 and forwarding application
>>> requests
>>>>> (/rs-test/*) to TomEE via AJP. TomEE is listening on ports 8080 for
>>> HTTP
>>>>> and 8009 for AJP requests. If the UriInfo matched the request info,
>>> then
>>>>> the port number given should be 8080 when loading an app from TomEE
>>>>> directly, and 8888 when using httpd to load the app via AJP.
>>>>> 
>>>>> When I request http://servername:8080/rs-**test/<
>>> http://servername:8080/rs-test/>to get content directly from TomEE via
>>> HTTP, the UriInfo methods match the
>>>>> request info, which also matches the server.xml host name and HTTP
>>>>> connector port (8080). But when I request http://servername:8888/rs-**
>>>>> test/ <http://servername:8888/rs-test/> to get content from TomEE
over
>>>>> AJP, UriInfo still lists the HTTP connector port (8080) instead of the
>>>>> request port (8888). The HttpServletRequest and HttpHeaders objects do
>>>>> return the request port, but UriInfo does not.
>>>>> 
>>>>> What I tried:
>>>>> 
>>>>> 1. Set up the environment
>>>>>       1. export TESTDIR=/tmp/test
>>>>>       2. mkdir -p $TESTDIR
>>>>>       3. export JDK_HOME=/opt/java/jdk1.7.0_11
>>>>>       4. export PATH=$JDK_HOME/bin:$PATH
>>>>> 2. Download, build, and install Apache httpd
>>>>>       1. Download and unpack httpd-2.2.23.tar.bz2
>>>>>       2. cd httpd-2.2.23
>>>>>       3. ./configure --prefix=$TESTDIR/httpd
>>>>>       4. make && make install
>>>>> 3. Download, build, and install mod_jk
>>>>>       1. Download and unpack tomcat-connectors-1.2.37-src.**tar.gz
>>>>>       2. cd tomcat-connectors-1.2.37-src/**native
>>>>>       3. ./configure --with-apxs=$TESTDIR/httpd/**bin/apxs
>>>>>       4. make && cp apache-2.0/mod_jk.so $TESTDIR/httpd/modules/
>>>>> 4. Download and unpack apache-tomee-1.5.1-jaxrs.tar.**gz
>>>>> 5. Configure Apache httpd
>>>>>       1. Edit $TESTDIR/httpd/conf/httpd.conf
>>>>>             1. Change Listen setting to port 8888 on public IP
>>>>>             2. Append the following to load and configure mod_jk:
>>>>> 
>>>>>          LoadModule jk_module modules/mod_jk.so
>>>>>          JkWorkersFile $TESTDIR/httpd/conf/workers.**properties
>>>>>          JkShmFile $TESTDIR/httpd/logs/mod_jk.shm
>>>>>          JkLogFile $TESTDIR/httpd/logs/mod_jk.log
>>>>>          JkLogLevel info
>>>>>          JkLogStampFormat "[%a %b %d %H:%M:%S %Y] "
>>>>>          JkMount /rs-test/* worker1
>>>>> 
>>>>>       2. Create $TESTDIR/httpd/conf/workers.**properties with the
>>>>>          following content:
>>>>> 
>>>>>          worker.list=worker1
>>>>>          worker.worker1.type=ajp13
>>>>>          worker.worker1.host=localhost
>>>>>          worker.worker1.port=8009
>>>>> 
>>>>> 6. Configure TomEE and create test app
>>>>>       1. Edit conf/server.xml:
>>>>>             1. Add jvmRoute="worker1" to engine configuration
>>>>>             2. Change Engine "defaultHost" and Host "name" values to
>>>>>                external host name
>>>>>       2. Create test application
>>>>>             1. Create webapps/rs-test/WEB-INF/**classes/test
>>> directory.
>>>>>             2. Create
>>> webapps/rs-test/WEB-INF/**classes/test/TestRS.java
>>>>> with
>>>>>                the following content:
>>>>> 
>>>>>          package test;
>>>>>          import java.net.URI;
>>>>>          import javax.servlet.http.**HttpServletRequest;
>>>>>          import javax.ws.rs.*;
>>>>>          import javax.ws.rs.core.*;
>>>>>          @Path("")
>>>>>          public class TestRS {
>>>>> 
>>>>>              @GET
>>>>>              @Produces({MediaType.TEXT_**PLAIN})
>>>>>              public String defaultPage(@Context UriInfo uriInfo,
>>>>>                    @Context HttpHeaders hh, @Context
>>>>>          HttpServletRequest httpServletRequest) {
>>>>>                 String response =
>>>>>                    "uriInfo.getAbsolutePath(): "
>>>>>                       + uriInfo.getAbsolutePath() + "\n"
>>>>>                    + "uriInfo.getBaseUri(): "
>>>>>                       + uriInfo.getBaseUri() + "\n"
>>>>>                    + "uriInfo.getRequestUri(): "
>>>>>                       + uriInfo.getRequestUri() + "\n"
>>>>>                    + "httpServletRequest.**getLocalAddr(): "
>>>>>                       + httpServletRequest.**getLocalAddr() + "\n"
>>>>>                    + "httpServletRequest.**getLocalName(): "
>>>>>                       + httpServletRequest.**getLocalName() + "\n"
>>>>>                    + "httpServletRequest.**getLocalPort(): "
>>>>>                       + httpServletRequest.**getLocalPort() + "\n"
>>>>>                    + "httpServletRequest.**getServerName(): "
>>>>>                       + httpServletRequest.**getServerName() + "\n"
>>>>>                    + "httpServletRequest.**getServerPort(): "
>>>>>                       + httpServletRequest.**getServerPort() + "\n\n";
>>>>>                 for (String header :
>>> hh.getRequestHeaders().keySet(**))
>>>>> {
>>>>>                    response += header + ":\n";
>>>>>                    for (String value :
>>>>>          hh.getRequestHeaders().get(**header)) {
>>>>>                       response += "\t" + value + "\n";
>>>>>                    }
>>>>>                 }
>>>>>                 return response;
>>>>>              }
>>>>>          }
>>>>> 
>>>>>         3. Compile test class with javac -classpath
>>>>>            lib/javaee-api-6.0-4-tomcat.**jar:lib/servlet-api.jar
>>>>>            webapps/rs-test/WEB-INF/**classes/test/TestRS.java
>>>>> 
>>>>> 7. Start services
>>>>>       1. Run apache-tomee-jaxrs-1.5.1/bin/**startup.sh to start TomEE
>>>>>       2. Run httpd/bin/apachectl start to start httpd.
>>>>> 
>>>>> 
>>>>> 
>>>>> On Wed, Feb 6, 2013 at 1:17 AM, Romain Manni-Bucau <
>>> rmannibucau@gmail.com<mailto:
>>>>> rmannibucau@gmail.com>**> wrote:
>>>>> 
>>>>>  UriInfo matches the http request info...
>>>>>  Le 6 févr. 2013 07:16, "Chet Hosey" <ChetHosey@gmail.com
>>>>>  <mailto:ChetHosey@gmail.com>> a écrit :
>>>>> 
>>>>> 
>>>>>> After building httpd 2.2.23 and mod_jk 1.2.37, I configured an
>>>>>  AJP proxy
>>>>>> for the TomEE test instance and set the jvmRoute in server.xml to
>>>>>  match the
>>>>>> worker name from workers.properties.
>>>>>> 
>>>>>> A request through httpd shows httpd's port number for the
>>>>>> httpServletRequest methods, but still shows the TomEE HTTP
>>>>>  connector port
>>>>>> in the URIs returned by the uriInfo methods.
>>>>>> 
>>>>>> Doing string replacements seems fairly inelegant but I suppose
>>>>>  it's an
>>>>>> option for custom apps. It would be surprising to learn that the
>>>>>  only other
>>>>>> option is to configure the TomEE instances' HTTP connectors on
>>>>>  the same
>>>>>> port as the httpd server, since each TomEE instance would then need
a
>>>>>> dedicated IP.
>>>>>> 
>>>>>> I've filed TOMEE-757 in JIRA, as it's hard to imagine that this
>>>>>  behavior is
>>>>>> intended.
>>>>>> 
>>>>>> 
>>>>>> On Tue, Feb 5, 2013 at 9:17 AM, Chet Hosey <ChetHosey@gmail.com
>>>>>  <mailto:ChetHosey@gmail.com>> wrote:
>>>>>> 
>>>>>>> Ahh, that's a good thought. It was the default value of
>>>>>  "localhost".
>>>>>> After
>>>>>>> changing the "name" attribute on the Host entry and updating
the
>>>>>>> defaultHost on the Engine, I'm getting the expected host name
>>>>>  in the
>>>>>>> response.
>>>>>>> 
>>>>>>> This leads me to wonder what happens when using AJP. I'm
>>>>>  picturing a
>>>>>> setup
>>>>>>> where httpd runs on port 80 and proxies to multiple TomEE
>>>>>  instances via
>>>>>>> AJP. If the HTTP connector port is still used by the UriInfo
>>>>>  methods,
>>>>>> then
>>>>>>> TomEE would require special access (root or authbind) to bind
>>>>>  to port 80
>>>>>> to
>>>>>>> work around this behavior. And it wouldn't be possible to run
>>>>>  multiple
>>>>>>> TomEE instances on the same IP, since they'd all have to bind
>>>>>  to port 80
>>>>>> to
>>>>>>> ensure URI correctness.
>>>>>>> 
>>>>>>> I'll have to experiment to find out. If I get the chance to do
>>>>>  so, I'll
>>>>>>> report results back.
>>>>>>> 
>>>>>>> Thanks!
>>>>>>> 
>>>>>>> 
>>>>>>> On Tue, Feb 5, 2013 at 1:16 AM, Romain Manni-Bucau <
>>>>>> rmannibucau@gmail.com <mailto:rmannibucau@gmail.com>**>wrote:
>>>>> 
>>>>>>> 
>>>>>>>> Hi,
>>>>>>>> 
>>>>>>>> What's your host in the server.xml?
>>>>>>>> Le 5 févr. 2013 06:30, "Chet Hosey" <ChetHosey@gmail.com
>>>>>  <mailto:ChetHosey@gmail.com>> a écrit :
>>>>> 
>>>>>>>> 
>>>>>>>>> I've been using apache-tomee-1.5.1-jaxrs as a platform
for
>>>>>  learning
>>>>>>>> JAX-RS
>>>>>>>>> and have run into some confusion about UriInfo determines
>>>>>  the base
>>>>>> URI.
>>>>>>>> In
>>>>>>>>> my testing the URIs returned by UriInfo include the correct
port
>>>>>> number.
>>>>>>>>> But the host name is always "localhost", even when I'm
>>>>>  accessing TomEE
>>>>>>>> from
>>>>>>>>> a remote machine.
>>>>>>>>> 
>>>>>>>>> It's possible that UriInfo is meant to build identifiers,
>>>>>  and not
>>>>>>>> locators.
>>>>>>>>> This would explain why it's not called UrlInfo. But the
>>>>>  design of
>>>>>>>>> UriBuilder suggests that one should be able to call
>>>>>>>>> 
>>>>>>>>>  uriInfo.getBaseUriBuilder()
>>>>>>>>>        .path(User.class, "getUserInfo")
>>>>>>>>>        .path(userId).build();
>>>>>>>>> 
>>>>>>>>> and use the result as a hyperlink in a JAX-RS response.
>>>>>>>>> 
>>>>>>>>> Having used mod_jk with JBoss, I know that it can override
>>>>>  the values
>>>>>>>>> returned by HttpServletRequest methods with parameters
like
>>>>>>>> JK_LOCAL_NAME.
>>>>>>>>> But since this is just a sandbox I'm accessing Tomcat
directly,
>>>>>> without
>>>>>>>> an
>>>>>>>>> Apache httpd proxy. But this led me to wonder what
>>>>>>>>> httpServletRequest.**getlocalName() would return. So
I created
>>>>>  a test
>>>>>>>> method
>>>>>>>>> to find out, using the following signature:
>>>>>>>>> 
>>>>>>>>>  @GET
>>>>>>>>>  @Produces({MediaType.TEXT_**PLAIN})
>>>>>>>>>  public String defaultPage(@Context UriInfo uriInfo,
>>>>>>>>>        @Context HttpHeaders hh,
>>>>>>>>>        @Context HttpServletRequest httpServletRequest)
{
>>>>>>>>> 
>>>>>>>>> The output surprised me. The HttpServletRequest methods
use the
>>>>>> correct
>>>>>>>>> host name and IP address, and the "Host" header uses
the public
>>>>>> address.
>>>>>>>>> The UriInfo methods get the port correct, but they still
use
>>>>>>>> "localhost" as
>>>>>>>>> the host name.
>>>>>>>>> 
>>>>>>>>>  uriInfo.getAbsolutePath():
>>>>>>>>> http://localhost:8081/sample-**app-1.0-SNAPSHOT/<
>>> http://localhost:8081/sample-app-1.0-SNAPSHOT/>
>>>>>>>>>  uriInfo.getBaseUri():
>>>>>> http://localhost:8081/sample-**app-1.0-SNAPSHOT<
>>> http://localhost:8081/sample-app-1.0-SNAPSHOT>
>>>>>>>>>  uriInfo.getRequestUri():
>>>>>>>> http://localhost:8081/sample-**app-1.0-SNAPSHOT/<
>>> http://localhost:8081/sample-app-1.0-SNAPSHOT/>
>>>>>>>>>  httpServletRequest.**getLocalAddr(): 1.2.3.4
>>>>>>>>>  httpServletRequest.**getLocalName(): www.example.com
>>>>>  <http://www.example.com>
>>>>>>>>>  httpServletRequest.**getLocalPort(): 8081
>>>>>>>>>  httpServletRequest.**getServerName(): www.example.com
>>>>>  <http://www.example.com>
>>>>>>>>>  httpServletRequest.**getServerPort(): 8081
>>>>>>>>> 
>>>>>>>>>  host:
>>>>>>>>> www.example.com:8081 <http://www.example.com:8081>
>>>>> 
>>>>>>>>> 
>>>>>>>>> Is there a way to use TomEE's embedded CXF REST
>>>>>  implementation to
>>>>>>>> generate
>>>>>>>>> URIs that can be used by external clients to locate other
>>>>>  resources
>>>>>>>> within
>>>>>>>>> the same application? Or am I making bad assumptions
about
>>>>>  the purpose
>>>>>>>> of
>>>>>>>>> the UriInfo methods that return UriBuilders?
>>>>>>>>> 
>>>>>>>>> -- Chet
>>>>>>>>> 
>>>>>>>> 
>>>>>>> 
>>>>>>> 
>>>>>> 
>>>>> 
>>>>> 
>>>>> 
>>> 
>>> 


Mime
View raw message