Hi all,

A possible use case for building a relative URI can be, for instance, to issue a redirect as a response to servlet request. We can, of course, extract the URL from the ServletRequest and create a UriBuilder from it (I never said that there was not a workaround, after all :D), but it's also perfectly valid to call HttpServletResponse#sendRedirect(String) with a relative URL. That's was actually my first idea, until I found the bug.

I don't see why the UriBuilder may get confused, when the URI class does not. The URI opaque="mailto:[email protected]?query=queryvalue#fragment"; has the following components:

 * Scheme: mailto
 * Scheme-specific part: [email protected]?query=queryvalue
 * Authority: null
 * Path: null
 * Query: null
 * Fragment: fragment

, while the URI "nonOpaque" defined as new URI(null, opaque.getSchemeSpecificPart(), opaque.getFragment()) has these:

 * Scheme: null
 * Scheme-specific part: [email protected]?query=queryvalue
 * Authority: null
 * Path: [email protected]
 * Query: query=queryvalue
 * Fragment: fragment

The "UriBuilder#uri" method says:
Copies the non-null components of the supplied URI to the UriBuilder replacing any existing values for those components.
So, the way I see it is:

1. If the provided URI is opaque, the UriBuilder's new URI should be:
   URI(scheme, schemeSpecificPart, fragment), where schemeSpecificPart
   is the provided URI's (because that component can never be null),
   while the scheme and fragment parts are those of the provided URI,
   unless any of them is null, in which case the corresponding
   component of the UriBuilder's URI will be used.
2. If the provided URI is not opaque, then you should use the
   constructor URI(scheme, authority, path, query, fragment)|| if the
   provided URI's authority is null (in which case the authority used
   should be the UriBuilder's). Path, query and fragment should be
   checked the same way.
3. If the provided URI is not opaque, and the provided URI's authority
   is not null, then you should use the constructor URI(scheme,
   userInfo, host, port, path, query, fragment), where each component
   belongs to the provided URI, unless that specific component is null.
   I am not sure how to proceed with the port, because it can never be
   null, so I guess it always gets overwritten.

When I mention the constructors, what I mean is "the URI backing the UriBuilder should be constructed this way", or "the URI represented by the current state of the UriBuilder should be constructed this way".


I think that algorithm correctly in the problematic cases you mentioned and should not break any more usual use cases. What do you think?


Cheers


P.S: By the way, the RFC-3986 (https://tools.ietf.org/html/rfc3986) obsoletes RFC-2396 (https://tools.ietf.org/html/rfc2396), on which the current Java's URI implementation is based. In the new RFC, the structure is much better explained IMHO. For instance, it is clearly said that the path of a URI is never undefined, although it can be empty, the concept of "opaque URIs" disappear, and instead "opaque paths" are mentioned (i.e. "mailto:[email protected]"; is no longer an opaque URI, but a URI with an opaque --or "non hierarchical"-- path). That does not help much in this case since UriBuilder should cope with the particularities of the current URI implementation anyway.


On 20/06/17 13:05, Sergey Beryozkin wrote:
Hi Gary

It was provided at the start of this thread, in general, if one has something like

UriBuilder.fromUri("relativePath")

then the subsequent builder update methods have no effect because the implementation treats this case as if URI has been opaque.


I'm not sure why do in the real code something like

UriBuilder.fromUri("relativePath").queryParam("name", "value")

as opposed to

UriBuilder.fromUri("http://host/relativePath";).queryParam("name", "value")

but purely from the techincal point of view I guess CXF UriBuilder impl should support this case...

Cheers, Sergey
On 20/06/17 03:56, Gary Gregory wrote:
Hi Sergey,

Can you formulate the issue you are seeing in the form of a failing unit
test?

Gary

On Mon, Jun 19, 2017 at 9:02 AM, Sergey Beryozkin <[email protected]>
wrote:

Hi

Awhile back, may be 5-6 years back, I had to deal with the following TCK
test:

             assertEquals("mailto:[email protected]";,

UriBuilder.fromUri(new URI("mailto:[email protected]";)).uri(new
URI(null, "[email protected]", null)).
                     build();


new URI("mailto:[email protected]";) is opaque, while
new URI(null, "[email protected]", null) is not.

At a time I found that the only way for this test to pass was to block any rawPaths not starting from "/" causing the confusion in the code, such that
in this test, when

new URI(null, "[email protected]", null).

is submitted, the original "mailto" scheme is preserved, and the original scheme specific part, "[email protected]" is overridden as expected, otherwise there would be some 'conflict; in the internal state, after the 1st pass the 'path' is undefined because it was an opaque URI, and in the
second pass we suddenly get a path component value which is meant to
replace an origin schemeSpecificPart where the path component was not even
defined...

I realize that is not the most robust approach, but that worked at a time.

I see that UriBuilder.fromPath() does work in this case.

Can you think of the fix that can address your issue such that the
original UriBuilderImplTest tests continue passing ?

Thanks, Sergey




On 17/06/17 00:23, Rubén Pérez wrote:

Hi,

Sorry for the double mail.

I forgot to add that, while I know the .jar versions are not the latest,
I checked the code in Fisheye and from what I understood the issue
corresponds with the latest code. The problems seems to arise from the code
in the line 627 <https://fisheye.apache.org/br
owse/cxf/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxr
s/impl/UriBuilderImpl.java?hb=true#to627> [2]: if the path does not
start with a "/", the varirable schemeSpecificPart is set to null, which in
turn prevents the code block in the line 161 <
https://fisheye.apache.org/browse/cxf/rt/frontend/jaxrs/src
/main/java/org/apache/cxf/jaxrs/impl/UriBuilderImpl.java?hb=true#to161>
[3] to run.

Regards


On 16/06/17 23:52, Rubén Pérez wrote:


Hi,

This is my first email to the list, so I hope I will not miss something
or do something wrong. I'm writing here instead of reporting a bug
directly, mainly because I'm not sure if I can even register in the bug
tracker, so apologies if that was the expected way to go.

Cutting to the chase, I believe there is a bug in the UriBuilderImpl.
Specifically, when an instance of the class is created through the
'.fromURI' method, and the provided URI does not start with a "/" (i.e. it has no schema and authority and its path is not absolute), UriBuilderImpl assumes incorrectly that the URI is non-hierarchical and therefore the '.build()' method will always return the provided URI without modification, regardless of which edit methods (e.g. "queryParam", "path", etc.) are
called on the instance.

In order to illustrate what I mean, I created a very simple program
(attached). I compiled it with:

     javac -cp '.:<path_to_the_jar>/javax.ws.rs-api-2.0.1.jar'
UriBuilderBug.java

and runned it with:

     java -cp '.:/<path_to_the_jar>/javax.ws
.rs-api-2.0.1.jar:<path_to_the_jar2>/cxf-rt-frontend-jaxrs-
3.1.11.jar:<path_to_the_jar3>/cxf-core-3.1.11.jar' UriBuilderBug

The RFC-3986, in its section 4.2 <https://tools.ietf.org/html/r
fc3986#section-4.2> [1] defines the syntax for valid relative URI
references and explicitly allows references without schema or authority that do *not* start with a forward slash. Perhaps part of the confusion comes from the fact that the ABNF defining the relative references is as
follows:

     relative-part = "//" authority path-abempty
                    / path-absolute
                    / path-noscheme
                    / path-empty

, where the "/" symbol representing the different alternatives can be
easily mistaken for a literal "/" in the URI itself.

So that's it. Thanks for reading till here. Please let know your
opinions about this and, if I'm right, it would be great to get it fixed soon. If something is not clear or you have any questions, I'm willing to answer them. If there's a reason for the current behaviour, or if I am
incorrectly interpreting the standard, I'd also be very glad to know.

Best regards
--
Rubén Pérez Vázquez

*Universität zu Köln*
/Regionales Rechenzentrum (RRZK)/
Weyertal 121, Raum 4.05
D-50931 Köln
✆: +49-221-470-89603

[1] https://tools.ietf.org/html/rfc3986#section-4.2




--
Sergey Beryozkin

Talend Community Coders
http://coders.talend.com/



--
Rubén Pérez Vázquez

*Universität zu Köln*
/Regionales Rechenzentrum (RRZK)/
Weyertal 121, Raum 4.05
D-50931 Köln
✆: +49-221-470-89603

[1] https://tools.ietf.org/html/rfc2396
[2] https://tools.ietf.org/html/rfc3986

Reply via email to