You are viewing a plain text version of this content. The canonical link for it is here.
Posted to users@cxf.apache.org by Aki Yoshida <el...@googlemail.com> on 2011/05/10 20:38:26 UTC

strange destination determination logic used by the osgi based cxf entry point

Hi,
I noticed this behavior with CXF 2.3.4 under OSGi. I think it is
strange. But there might be some explanation or I am missing
something.

Basically, the problem is described as follows. When I have a CXF
endpoint registered at a particular URL path, I can send a SOAP
message to this service by sending it to any URL path that starts with
this path. I stumbled on this problem when I had two paths registered
(something like /soappath and /soappath2 using two bundles,
respectively). When I stopped the second bundle and sent a message to
/soappath2, expecting to see the message being rejected, instead the
message was simply forwarded to the service under the first
destination /soappath.

Then, I saw the following method in
org.apache.cxf.transport.http_osgi.OsgiServletController that was
responsible for this fallback logic.

    private OsgiDestination checkRestfulRequest(HttpServletRequest
request) throws IOException {

        String address = request.getPathInfo() == null ? "" :
request.getPathInfo();

        for (String path : servlet.getTransport().getDestinationsPaths()) {
            if (address.startsWith(path)) {
                return servlet.getTransport().getDestinationForPath(path);
            }
        }
        return null;
    }

Note that I am using the SOAP binding and sending SOAP messages to
these entry points.

In 3.4.0, this OsgiServeltController class is no longer used, but when
a call enters over
org.apache.cxf.transport.servlet.ServletController's
invoke(HttpServletRequest, HttpServletResponse) method, this method
invokes an equivalent method implemented in
org.apache.cxf.transport.http.DestinationRegistryImpl

    public AbstractHTTPDestination checkRestfulRequest(String address) {
        int len = -1;
        AbstractHTTPDestination ret = null;
        for (String path : getDestinationsPaths()) {
            if (address.startsWith(path)
                && path.length() > len) {
                ret = getDestinationForPath(path);
                len = path.length();
            }
        }
        if (ret != null && ret.getMessageObserver() == null) {
            return null;
        }
        return ret;
    }

What is not clear to me is why this logic is used also for normal SOAP
calls in the OSGi setup but not in the standalone setup using
http_jetty.
Could someone tell me why we have this destination finding logic here?

I think this fallback logic should not be the default even if it is
desired in some cases. But I am interested in hearing your opinons.

Thanks.
Regards, aki

Re: strange destination determination logic used by the osgi based cxf entry point

Posted by Sergey Beryozkin <sb...@gmail.com>.
Hi Aki

On Wed, May 11, 2011 at 1:53 PM, Aki Yoshida <el...@googlemail.com> wrote:
> Hi Sergey,
> I think it will be slightly complicated to describe the logic in a
> short sentense.
> As I see, we need to make sure the matching works for the following cases.
>
> Suppose we have the registered services at
> "/soap", "/soap2", "/soappath", "/soap/test".
>
> we should have the matching match(address) -> the registered path with
>
> match("/soap") -> "/soap"
> match("/soap/2") -> "/soap"
> match("/soap/") -> "/soap"
> match("/soap2") -> "/soap2"
> match("/soap3") -> null
> match("/soap/test") -> "/soap/test"
> match("/soap/tst") -> "/soap"
>
> Basically, we need to check if the address is identical to the path or
> starts with the path + "/".
> A special case is when the address ends with an "/" as in the third
> case above, which needs to be matched against the path using only the
> part preceeding to the "/".
>
> I'll create a jira ticket and suggest a possible solution.
>
Sounds good

> In addition, we might still need an exact matching option if people
> are not happy with the call to "/soap/test" suddenly forwarded to
> "/soap" as in the last case intead of getting rejected when we
> unregister the service at "/soap/test". Or is this behavior accepted
> or even expected? I think we can live with this behavior, but I am not
> sure what others think.
>
I agree, I briefly referred to it, it should be possible to configure
either CXFServlet or individual
endpoint for a strict match policy be enforced. May be if we have a
servlet parameter in place then the policy is global and applies to
all of the endpoints, and if it's an endpoint property then it applies
to a particular Destination only ?

thanks, Sergey

> regards, aki
>
> 2011/5/11 Sergey Beryozkin <sb...@gmail.com>:
>>>
>>> Aki, in the code you posted,
>>>
>>> for (String path : getDestinationsPaths()) {
>>>           if (address.startsWith(path)
>>>               && path.length() > len) {
>>>               ret = getDestinationForPath(path);
>>>               len = path.length();
>>>           }
>>>       }
>>>
>>> It should probably be just
>>>
>>> if (path.startsWith(adddress)
>>>
>>> That will make sure /soapaddress destinations won't catch
>>> /soapaddress2 requests but will /soapaddress/1.
>>>
>> Sorry, I got confused, the above suggestion is also incorrect :-).
>>
>> Given /soapaddress2 and destination address /soapaddress,
>> path.startsWith(adddress) would fix it but we'd get /soapaddress
>> delivered to /soapaddress2 destinations, so as you suggested, the
>> address (/soapaddress2 or /soapaddress2/2) has to be split into
>> segments and the first segment needs to match exactly the endpoint
>> address, that should probably work, what do you think ?
>>
>> thanks, Sergey
>>
>

Re: strange destination determination logic used by the osgi based cxf entry point

Posted by Aki Yoshida <el...@googlemail.com>.
Hi Sergey,
I think it will be slightly complicated to describe the logic in a
short sentense.
As I see, we need to make sure the matching works for the following cases.

Suppose we have the registered services at
"/soap", "/soap2", "/soappath", "/soap/test".

we should have the matching match(address) -> the registered path with

match("/soap") -> "/soap"
match("/soap/2") -> "/soap"
match("/soap/") -> "/soap"
match("/soap2") -> "/soap2"
match("/soap3") -> null
match("/soap/test") -> "/soap/test"
match("/soap/tst") -> "/soap"

Basically, we need to check if the address is identical to the path or
starts with the path + "/".
A special case is when the address ends with an "/" as in the third
case above, which needs to be matched against the path using only the
part preceeding to the "/".

I'll create a jira ticket and suggest a possible solution.

In addition, we might still need an exact matching option if people
are not happy with the call to "/soap/test" suddenly forwarded to
"/soap" as in the last case intead of getting rejected when we
unregister the service at "/soap/test". Or is this behavior accepted
or even expected? I think we can live with this behavior, but I am not
sure what others think.

regards, aki

2011/5/11 Sergey Beryozkin <sb...@gmail.com>:
>>
>> Aki, in the code you posted,
>>
>> for (String path : getDestinationsPaths()) {
>>           if (address.startsWith(path)
>>               && path.length() > len) {
>>               ret = getDestinationForPath(path);
>>               len = path.length();
>>           }
>>       }
>>
>> It should probably be just
>>
>> if (path.startsWith(adddress)
>>
>> That will make sure /soapaddress destinations won't catch
>> /soapaddress2 requests but will /soapaddress/1.
>>
> Sorry, I got confused, the above suggestion is also incorrect :-).
>
> Given /soapaddress2 and destination address /soapaddress,
> path.startsWith(adddress) would fix it but we'd get /soapaddress
> delivered to /soapaddress2 destinations, so as you suggested, the
> address (/soapaddress2 or /soapaddress2/2) has to be split into
> segments and the first segment needs to match exactly the endpoint
> address, that should probably work, what do you think ?
>
> thanks, Sergey
>

Re: strange destination determination logic used by the osgi based cxf entry point

Posted by Sergey Beryozkin <sb...@gmail.com>.
>
> Aki, in the code you posted,
>
> for (String path : getDestinationsPaths()) {
>           if (address.startsWith(path)
>               && path.length() > len) {
>               ret = getDestinationForPath(path);
>               len = path.length();
>           }
>       }
>
> It should probably be just
>
> if (path.startsWith(adddress)
>
> That will make sure /soapaddress destinations won't catch
> /soapaddress2 requests but will /soapaddress/1.
>
Sorry, I got confused, the above suggestion is also incorrect :-).

Given /soapaddress2 and destination address /soapaddress,
path.startsWith(adddress) would fix it but we'd get /soapaddress
delivered to /soapaddress2 destinations, so as you suggested, the
address (/soapaddress2 or /soapaddress2/2) has to be split into
segments and the first segment needs to match exactly the endpoint
address, that should probably work, what do you think ?

thanks, Sergey

Re: strange destination determination logic used by the osgi based cxf entry point

Posted by Sergey Beryozkin <sb...@gmail.com>.
Hi Aki, Willem

Yes, exactly, you are right, that is how it should be implemented, it's obvious
that if we have "/soapaddress" then only /soapaddress/2 or
/soapaddress should be matched
against it.
I recall now why this code is executed for SOAP requests as well, to
handle SOAP GETs like
/soapaddress/methodname/parameterValue.

Aki, in the code you posted,

for (String path : getDestinationsPaths()) {
           if (address.startsWith(path)
               && path.length() > len) {
               ret = getDestinationForPath(path);
               len = path.length();
           }
       }

It should probably be just

if (path.startsWith(adddress)

That will make sure /soapaddress destinations won't catch
/soapaddress2 requests but will /soapaddress/1.

That said, the issue of strict matching may also need to be resolved
so that one can enforce that
/soapaddress catch only /soapaddress - but that is another issue

thanks, Sergey




On Wed, May 11, 2011 at 3:32 AM, Willem Jiang <wi...@gmail.com> wrote:
> +1 to check the address path which is starting with "/rest/".
> It's more make sense for us.
>
>
> On 5/11/11 5:48 AM, Aki Yoshida wrote:
>>
>> Hi Sergey,
>> Thanks for your explanation. I suspected of such a fallback logic. But
>> should this fallback work for an arbitrary string or only for path
>> segments. For example, in your example, if the rest service is
>> registered at "/rest", a request to "/rest/1/2" should be sent to this
>> service but how about a request to "/rest234"?
>>
>> If we do not foward such a request but only foward those with the
>> matching path segments, can we just do the check for whether the
>> address path is starting with "/rest/" or identical to "/rest"?
>>
>> Thanks.
>> Regards, aki
>
>
> --
> Willem
> ----------------------------------
> FuseSource
> Web: http://www.fusesource.com
> Blog:    http://willemjiang.blogspot.com (English)
>         http://jnn.javaeye.com (Chinese)
> Twitter: willemjiang
>
> Connect at CamelOne May 24-26
> The Open Source Integration Conference
> http://camelone.com
>

Re: strange destination determination logic used by the osgi based cxf entry point

Posted by Willem Jiang <wi...@gmail.com>.
+1 to check the address path which is starting with "/rest/".
It's more make sense for us.


On 5/11/11 5:48 AM, Aki Yoshida wrote:
> Hi Sergey,
> Thanks for your explanation. I suspected of such a fallback logic. But
> should this fallback work for an arbitrary string or only for path
> segments. For example, in your example, if the rest service is
> registered at "/rest", a request to "/rest/1/2" should be sent to this
> service but how about a request to "/rest234"?
>
> If we do not foward such a request but only foward those with the
> matching path segments, can we just do the check for whether the
> address path is starting with "/rest/" or identical to "/rest"?
>
> Thanks.
> Regards, aki


-- 
Willem
----------------------------------
FuseSource
Web: http://www.fusesource.com
Blog:    http://willemjiang.blogspot.com (English)
          http://jnn.javaeye.com (Chinese)
Twitter: willemjiang

Connect at CamelOne May 24-26
The Open Source Integration Conference
http://camelone.com

Re: strange destination determination logic used by the osgi based cxf entry point

Posted by Aki Yoshida <el...@googlemail.com>.
Hi Sergey,
Thanks for your explanation. I suspected of such a fallback logic. But
should this fallback work for an arbitrary string or only for path
segments. For example, in your example, if the rest service is
registered at "/rest", a request to "/rest/1/2" should be sent to this
service but how about a request to "/rest234"?

If we do not foward such a request but only foward those with the
matching path segments, can we just do the check for whether the
address path is starting with "/rest/" or identical to "/rest"?

Thanks.
Regards, aki

2011/5/10 Sergey Beryozkin <sb...@gmail.com>:
> Hi
>
> Please see comments inline
>
> On Tue, May 10, 2011 at 7:38 PM, Aki Yoshida <el...@googlemail.com> wrote:
>> Hi,
>> I noticed this behavior with CXF 2.3.4 under OSGi. I think it is
>> strange. But there might be some explanation or I am missing
>> something.
>>
>> Basically, the problem is described as follows. When I have a CXF
>> endpoint registered at a particular URL path, I can send a SOAP
>> message to this service by sending it to any URL path that starts with
>> this path. I stumbled on this problem when I had two paths registered
>> (something like /soappath and /soappath2 using two bundles,
>> respectively). When I stopped the second bundle and sent a message to
>> /soappath2, expecting to see the message being rejected, instead the
>> message was simply forwarded to the service under the first
>> destination /soappath.
>>
>> Then, I saw the following method in
>> org.apache.cxf.transport.http_osgi.OsgiServletController that was
>> responsible for this fallback logic.
>>
>>    private OsgiDestination checkRestfulRequest(HttpServletRequest
>> request) throws IOException {
>>
>>        String address = request.getPathInfo() == null ? "" :
>> request.getPathInfo();
>>
>>        for (String path : servlet.getTransport().getDestinationsPaths()) {
>>            if (address.startsWith(path)) {
>>                return servlet.getTransport().getDestinationForPath(path);
>>            }
>>        }
>>        return null;
>>    }
>>
>> Note that I am using the SOAP binding and sending SOAP messages to
>> these entry points.
>>
>> In 3.4.0, this OsgiServeltController class is no longer used, but when
>> a call enters over
>> org.apache.cxf.transport.servlet.ServletController's
>> invoke(HttpServletRequest, HttpServletResponse) method, this method
>> invokes an equivalent method implemented in
>> org.apache.cxf.transport.http.DestinationRegistryImpl
>>
>>    public AbstractHTTPDestination checkRestfulRequest(String address) {
>>        int len = -1;
>>        AbstractHTTPDestination ret = null;
>>        for (String path : getDestinationsPaths()) {
>>            if (address.startsWith(path)
>>                && path.length() > len) {
>>                ret = getDestinationForPath(path);
>>                len = path.length();
>>            }
>>        }
>>        if (ret != null && ret.getMessageObserver() == null) {
>>            return null;
>>        }
>>        return ret;
>>    }
>>
>> What is not clear to me is why this logic is used also for normal SOAP
>> calls in the OSGi setup but not in the standalone setup using
>> http_jetty.
>
> I'm not well aware of the how ServletController was evolving from the
> very start but I assume this code lives in ServletController for a
> default stem match to succeed, while in Jetty case it's all handled by
> Jetty itself, just one possible explanation.
> The above code is definitely needed for JAX-RS endpoints to work
> properly, ex, given jaxrs:server/@address = "/rest",
> /rest/1/2 will be matched against it.
>
> I think the above code executes in the case of SOAP requests because
> the initial check for available destination fails (no exact match for
> /soappath2) but I reckon the most effective option to block the above
> code from succeeding in this case is to configure a bundle specific
> Destination to use the strict match in checkRestfulRequest. That will
> definitely work, the other option is to check the Content-Type but
> it's not 100% guaranteed to be a SOAP endpoint that is going
> to handle it...
>
> Would you agree that selectively setting a strict match policy will
> fix the issue ?
>
> Cheers, Sergey
>
>> Could someone tell me why we have this destination finding logic here?
>>
>> I think this fallback logic should not be the default even if it is
>> desired in some cases. But I am interested in hearing your opinons.
>>
>> Thanks.
>> Regards, aki
>>
>
>
>
> --
> Sergey Beryozkin
>
> Application Integration Division of Talend
> http://sberyozkin.blogspot.com
>

Re: strange destination determination logic used by the osgi based cxf entry point

Posted by Sergey Beryozkin <sb...@gmail.com>.
Hi

Please see comments inline

On Tue, May 10, 2011 at 7:38 PM, Aki Yoshida <el...@googlemail.com> wrote:
> Hi,
> I noticed this behavior with CXF 2.3.4 under OSGi. I think it is
> strange. But there might be some explanation or I am missing
> something.
>
> Basically, the problem is described as follows. When I have a CXF
> endpoint registered at a particular URL path, I can send a SOAP
> message to this service by sending it to any URL path that starts with
> this path. I stumbled on this problem when I had two paths registered
> (something like /soappath and /soappath2 using two bundles,
> respectively). When I stopped the second bundle and sent a message to
> /soappath2, expecting to see the message being rejected, instead the
> message was simply forwarded to the service under the first
> destination /soappath.
>
> Then, I saw the following method in
> org.apache.cxf.transport.http_osgi.OsgiServletController that was
> responsible for this fallback logic.
>
>    private OsgiDestination checkRestfulRequest(HttpServletRequest
> request) throws IOException {
>
>        String address = request.getPathInfo() == null ? "" :
> request.getPathInfo();
>
>        for (String path : servlet.getTransport().getDestinationsPaths()) {
>            if (address.startsWith(path)) {
>                return servlet.getTransport().getDestinationForPath(path);
>            }
>        }
>        return null;
>    }
>
> Note that I am using the SOAP binding and sending SOAP messages to
> these entry points.
>
> In 3.4.0, this OsgiServeltController class is no longer used, but when
> a call enters over
> org.apache.cxf.transport.servlet.ServletController's
> invoke(HttpServletRequest, HttpServletResponse) method, this method
> invokes an equivalent method implemented in
> org.apache.cxf.transport.http.DestinationRegistryImpl
>
>    public AbstractHTTPDestination checkRestfulRequest(String address) {
>        int len = -1;
>        AbstractHTTPDestination ret = null;
>        for (String path : getDestinationsPaths()) {
>            if (address.startsWith(path)
>                && path.length() > len) {
>                ret = getDestinationForPath(path);
>                len = path.length();
>            }
>        }
>        if (ret != null && ret.getMessageObserver() == null) {
>            return null;
>        }
>        return ret;
>    }
>
> What is not clear to me is why this logic is used also for normal SOAP
> calls in the OSGi setup but not in the standalone setup using
> http_jetty.

I'm not well aware of the how ServletController was evolving from the
very start but I assume this code lives in ServletController for a
default stem match to succeed, while in Jetty case it's all handled by
Jetty itself, just one possible explanation.
The above code is definitely needed for JAX-RS endpoints to work
properly, ex, given jaxrs:server/@address = "/rest",
/rest/1/2 will be matched against it.

I think the above code executes in the case of SOAP requests because
the initial check for available destination fails (no exact match for
/soappath2) but I reckon the most effective option to block the above
code from succeeding in this case is to configure a bundle specific
Destination to use the strict match in checkRestfulRequest. That will
definitely work, the other option is to check the Content-Type but
it's not 100% guaranteed to be a SOAP endpoint that is going
to handle it...

Would you agree that selectively setting a strict match policy will
fix the issue ?

Cheers, Sergey

> Could someone tell me why we have this destination finding logic here?
>
> I think this fallback logic should not be the default even if it is
> desired in some cases. But I am interested in hearing your opinons.
>
> Thanks.
> Regards, aki
>



-- 
Sergey Beryozkin

Application Integration Division of Talend
http://sberyozkin.blogspot.com