Skip to content
This repository has been archived by the owner on May 28, 2018. It is now read-only.

Unable to parse "If-None-Match" header value #2511

Open
glassfishrobot opened this issue Nov 21, 2013 · 6 comments
Open

Unable to parse "If-None-Match" header value #2511

glassfishrobot opened this issue Nov 21, 2013 · 6 comments

Comments

@glassfishrobot
Copy link

If If-None-Match Header Etag content is sent without the quotes like c27b74582676d4cca1e35d3fd2171d5b , the request fail
If the content is sent with quotes like "c27b74582676d4cca1e35d3fd2171d5b" everything goes well.

The exception thrown:

Nov 21, 2013 8:10:03 PM org.glassfish.jersey.server.ServerRuntime$Responder mapException
WARNING: WebApplicationException cause:
org.glassfish.jersey.message.internal.HeaderValueException: Unable to parse "If-None-Match" header value: "c27b74582676d4cca1e35d3fd2171d5b"
	at org.glassfish.jersey.message.internal.InboundMessageContext.exception(InboundMessageContext.java:335)
	at org.glassfish.jersey.message.internal.InboundMessageContext.getIfNoneMatch(InboundMessageContext.java:396)
	at org.glassfish.jersey.server.ContainerRequest.evaluateIfNoneMatch(ContainerRequest.java:713)
	at org.glassfish.jersey.server.ContainerRequest.evaluatePreconditions(ContainerRequest.java:615)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
	at java.lang.reflect.Method.invoke(Unknown Source)
	at com.zeroturnaround.javarebel.BZ.invoke(JRebel:1062)
	at java.lang.reflect.Method.invoke(Unknown Source)
	at org.glassfish.jersey.server.model.internal.ResourceMethodInvocationHandlerFactory$1.invoke(ResourceMethodInvocationHandlerFactory.java:81)
	at org.glassfish.jersey.server.model.internal.AbstractJavaResourceMethodDispatcher$1.run(AbstractJavaResourceMethodDispatcher.java:151)
	at org.glassfish.jersey.server.model.internal.AbstractJavaResourceMethodDispatcher.invoke(AbstractJavaResourceMethodDispatcher.java:171)
	at org.glassfish.jersey.server.model.internal.JavaResourceMethodDispatcherProvider$ResponseOutInvoker.doDispatch(JavaResourceMethodDispatcherProvider.java:152)
	at org.glassfish.jersey.server.model.internal.AbstractJavaResourceMethodDispatcher.dispatch(AbstractJavaResourceMethodDispatcher.java:104)
	at org.glassfish.jersey.server.model.ResourceMethodInvoker.invoke(ResourceMethodInvoker.java:367)
	at org.glassfish.jersey.server.model.ResourceMethodInvoker.apply(ResourceMethodInvoker.java:349)
	at org.glassfish.jersey.server.model.ResourceMethodInvoker.apply(ResourceMethodInvoker.java:106)
	at org.glassfish.jersey.server.ServerRuntime$1.run(ServerRuntime.java:259)
	at org.glassfish.jersey.internal.Errors$1.call(Errors.java:271)
	at org.glassfish.jersey.internal.Errors$1.call(Errors.java:267)
	at org.glassfish.jersey.internal.Errors.process(Errors.java:315)
	at org.glassfish.jersey.internal.Errors.process(Errors.java:297)
	at org.glassfish.jersey.internal.Errors.process(Errors.java:267)
	at org.glassfish.jersey.process.internal.RequestScope.runInScope(RequestScope.java:318)
	at org.glassfish.jersey.server.ServerRuntime.process(ServerRuntime.java:236)
	at org.glassfish.jersey.server.ApplicationHandler.handle(ApplicationHandler.java:983)
	at org.glassfish.jersey.servlet.WebComponent.service(WebComponent.java:361)
	at org.glassfish.jersey.servlet.ServletContainer.service(ServletContainer.java:372)
	at org.glassfish.jersey.servlet.ServletContainer.service(ServletContainer.java:335)
	at org.glassfish.jersey.servlet.ServletContainer.service(ServletContainer.java:218)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:305)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:210)
	at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:222)
	at org.apache.catalina.core.StandardContextValve.__invoke(StandardContextValve.java:123)
	at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java)
	at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:502)
	at org.apache.catalina.core.StandardHostValve.__invoke(StandardHostValve.java:171)
	at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java)
	at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:99)
	at org.apache.catalina.valves.AccessLogValve.invoke(AccessLogValve.java:953)
	at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:118)
	at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:408)
	at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1023)
	at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:589)
	at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.run(NioEndpoint.java:1686)
	at java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source)
	at java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)
	at java.lang.Thread.run(Unknown Source)
Caused by: java.text.ParseException: Error parsing entity tag
	at org.glassfish.jersey.message.internal.MatchingEntityTag.valueOf(MatchingEntityTag.java:86)
	at org.glassfish.jersey.message.internal.HttpHeaderReader$1.create(HttpHeaderReader.java:298)
	at org.glassfish.jersey.message.internal.HttpHeaderReader$1.create(HttpHeaderReader.java:294)
	at org.glassfish.jersey.message.internal.HttpHeaderReader.readMatchingEntityTag(HttpHeaderReader.java:311)
	at org.glassfish.jersey.message.internal.InboundMessageContext.getIfNoneMatch(InboundMessageContext.java:394)

Environment

Windows 7 Ultimate Service Pack 1 64bit

Affected Versions

[2.4.1]

@glassfishrobot
Copy link
Author

Reported by lucianb

@glassfishrobot
Copy link
Author

michalgajdos said:
This behaviour is compliant with HTTP 1.1 spec (see [1]):

Entity tags are used for comparing two or more entities from the same requested resource. HTTP/1.1 uses entity tags in the ETag (section 14.19), If-Match (section 14.24), If-None-Match (section 14.26), and If-Range (section 14.27) header fields. The definition of how they are used and compared as cache validators is in section 13.3.3. An entity tag consists of an opaque quoted string, possibly prefixed by a weakness indicator.

entity-tag = [ weak ] opaque-tag
 weak       = "W/"
 opaque-tag = quoted-string

A "strong entity tag" MAY be shared by two entities of a resource only if they are equivalent by octet equality.

A "weak entity tag," indicated by the "W/" prefix, MAY be shared by two entities of a resource only if the entities are equivalent and could be substituted for each other with no significant change in semantics. A weak entity tag can only be used for weak comparison.

An entity tag MUST be unique across all versions of all entities associated with a particular resource. A given entity tag value MAY be used for entities obtained by requests on different URIs. The use of the same entity tag value in conjunction with entities obtained by requests on different URIs does not imply the equivalence of those entities.

[1] http://www.w3.org/Protocols/rfc2616/rfc2616-sec3.html#sec3.11

@glassfishrobot
Copy link
Author

michalgajdos said:
Moving to backlog and changing to improvement to see whether we could do something to make this more convenient.

@glassfishrobot
Copy link
Author

runarb said:
I think that we should expect a 400 Bad Request in this case.
The HeaderValueException could be caught in

ContainerRequest.evaluateIfNoneMatch(EntityTag eTag)

and a ResponseBuilder of 400 should be returned.

It feels wrong having to deal with this exception when "trusting" evaluateIfNoneMatch(..) to take care of handling the entity tag.

What do you think?

@glassfishrobot
Copy link
Author

avsokolov said:
I always get Bad Request, here is example of code:

@GET
    public Response getTemplate4CustomSkin(@Context final Request request)
    {
        EntityTag eTag = new EntityTag("123456789");
        Response.ResponseBuilder responseBuilder = request.evaluatePreconditions(eTag);
        if (responseBuilder == null)
        {
            System.out.printf("is null");
        }
        else
        {
            System.out.printf("is not null");
        }
        return Response.ok(data.inputStream, data.mimeType).tag(eTag).build();
    }
 }

    @Test
    public void testGetFileEtagIsNotChanged() throws UnsupportedEncodingException
    {
        Client client = ClientBuilder.newClient();
        WebTarget target = client.target("someUrl");
        EntityTag eTag = new EntityTag("123456789");
        Response response = target.request().get();
        //send request 2nd time with 
        response = target.request().header("If-None-Match", response.getEntityTag()).get();
        //same result 
        //response = target.request().header("If-None-Match", response.getEntityTag().getValue()).get();
        Assert.assertEquals(eTag, response.getEntityTag());
    }

// the following code always throws an exception inside of org.glassfish.jersey.message.internal.HttpHeaderReaderImpl.java class:
    private char getNextCharacter(boolean skipWhiteSpace) throws ParseException {
        ....
        // this line of code always throws it:
        if(this.index >= this.length) {
            throw new ParseException(LocalizationMessages.HTTP_HEADER_END_OF_HEADER(), this.index);
        } else {
            return this.header.charAt(this.index);
        }
    }

I run tests via arquillian, dependency versions:

<!--Arquillian JUnit integration: -->
        <dependency>
            <groupId>org.jboss.arquillian.junit</groupId>
            <artifactId>arquillian-junit-container</artifactId>
            <version>1.1.8.Final</version>
            <scope>test</scope>
        </dependency>
        <!--glassfish-embedded:-->
        <dependency>
            <groupId>org.glassfish.main.extras</groupId>
            <artifactId>glassfish-embedded-all</artifactId>
            <version>4.1</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.jboss.arquillian.container</groupId>
            <artifactId>arquillian-glassfish-embedded-3.1</artifactId>
            <version>1.0.0.CR4</version>
            <scope>test</scope>
        </dependency>

How can I resolve it? How can I send a request with "If-None-Match" header inlcuded and don't get an exception?

@glassfishrobot
Copy link
Author

This issue was imported from java.net JIRA JERSEY-2239

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

No branches or pull requests

2 participants