[TYRUS-212] Closing the Session in @OnOpen method blocks the whole HTTP server Created: 11/Jul/13  Updated: 11/Jul/13  Resolved: 11/Jul/13

Status: Resolved
Project: tyrus
Component/s: None
Affects Version/s: 1.0
Fix Version/s: 1.1

Type: Bug Priority: Critical
Reporter: kithouna Assignee: Pavel Bucek
Resolution: Duplicate Votes: 0
Labels: None
Remaining Estimate: Not Specified
Time Spent: Not Specified
Original Estimate: Not Specified
Environment:

GlassFish 4.0 on Windows 7 x64


Issue Links:
Duplicate
duplicates TYRUS-192 ServerEndpoint creates Session on #2 ... Resolved
Tags: close, glassfish, http, onopen, session, tyrus, websocket, websockets

 Description   

There may be reasons to close an incoming connection immediately, for example, when an application misconfiguration is detected and the request cannot be handled properly or because the Websocket client request is malformed (for example, a numeric @PathParam was expected but contained other characters). But doing this in the @OnOpen method makes the server hang, it is not reachable anymore (or at least very slow), even for non-Websocket requests. After 15 minutes, the server is reachable (and fast) again, but unstable. JSR-356 does not seem to forbid closing the Session in the @OnOpen method.

Example:

@ServerEndpoint("/ws/

{id}

")
public class MyEndpoint {
@OnOpen
public void onOpen(final Session session) {
System.out.println("closing");
try

{ session.close(); }

catch (IOException ex)

{ System.out.println("close exception"); // never called }

System.out.println("closed"); // called after 15 minutes
}

@OnClose
public void onClose()

{ System.out.println("onClose"); }

}

// server.log:

[2013-07-11T11:56:02.682+0000] [glassfish 4.0] [INFO] [] [] [tid: _ThreadID=101 _ThreadName=Thread-3] [timeMillis: 1373543762682] [levelValue: 800] [[
closing]]

// Note the 15 minute delay

[2013-07-11T12:11:02.877+0000] [glassfish 4.0] [INFO] [] [] [tid: _ThreadID=101 _ThreadName=Thread-3] [timeMillis: 1373544662877] [levelValue: 800] [[
closed]]

// Exception was generated:

[2013-07-11T12:11:02.877+0000] [glassfish 4.0] [SEVERE] [AS-WEB-CORE-00037] [javax.enterprise.web.core] [tid: _ThreadID=101 _ThreadName=http-listener-1(1)] [timeMillis: 1373544662877] [levelValue: 1000] [[
An exception or error occurred in the container during the request processing
java.lang.IllegalStateException: Internal org.glassfish.grizzly.http.server.Response has not been set
at org.glassfish.grizzly.http.server.Response.checkResponse(Response.java:1840)
at org.glassfish.grizzly.http.server.Response.getStatus(Response.java:968)
at org.apache.catalina.connector.Response.getStatus(Response.java:1070)
at org.apache.catalina.connector.CoyoteAdapter.doService(CoyoteAdapter.java:364)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:260)
at com.sun.enterprise.v3.services.impl.ContainerMapper.service(ContainerMapper.java:188)
at org.glassfish.grizzly.http.server.HttpHandler.runService(HttpHandler.java:191)
at org.glassfish.grizzly.http.server.HttpHandler.doHandle(HttpHandler.java:168)
at org.glassfish.grizzly.http.server.HttpServerFilter.handleRead(HttpServerFilter.java:189)
at org.glassfish.grizzly.filterchain.ExecutorResolver$9.execute(ExecutorResolver.java:119)
at org.glassfish.grizzly.filterchain.DefaultFilterChain.executeFilter(DefaultFilterChain.java:288)
at org.glassfish.grizzly.filterchain.DefaultFilterChain.executeChainPart(DefaultFilterChain.java:206)
at org.glassfish.grizzly.filterchain.DefaultFilterChain.execute(DefaultFilterChain.java:136)
at org.glassfish.grizzly.filterchain.DefaultFilterChain.process(DefaultFilterChain.java:114)
at org.glassfish.grizzly.ProcessorExecutor.execute(ProcessorExecutor.java:77)
at org.glassfish.grizzly.nio.transport.TCPNIOTransport.fireIOEvent(TCPNIOTransport.java:838)
at org.glassfish.grizzly.strategies.AbstractIOStrategy.fireIOEvent(AbstractIOStrategy.java:113)
at org.glassfish.grizzly.strategies.WorkerThreadIOStrategy.run0(WorkerThreadIOStrategy.java:115)
at org.glassfish.grizzly.strategies.WorkerThreadIOStrategy.access$100(WorkerThreadIOStrategy.java:55)
at org.glassfish.grizzly.strategies.WorkerThreadIOStrategy$WorkerThreadRunnable.run(WorkerThreadIOStrategy.java:135)
at org.glassfish.grizzly.threadpool.AbstractThreadPool$Worker.doWork(AbstractThreadPool.java:564)
at org.glassfish.grizzly.threadpool.AbstractThreadPool$Worker.run(AbstractThreadPool.java:544)
at java.lang.Thread.run(Thread.java:722)
]]

// @OnClose is called

[2013-07-11T12:11:02.877+0000] [glassfish 4.0] [FINEST] [] [org.example.MyEndpoint] [tid: _ThreadID=102 _ThreadName=http-listener-1(2)] [timeMillis: 1373544662877] [levelValue: 300] [CLASSNAME: org.example.MyEndpoint] [METHODNAME:

onClose] [[
onClose]]

// Now the JSF application sometimes displays an exception:

[2013-07-11T12:14:55.634+0000] [glassfish 4.0] [WARNING] [] [javax.enterprise.web.core] [tid: _ThreadID=101 _ThreadName=http-listener-1(1)] [timeMillis: 1373544895634] [levelValue: 900] [[
Error invoking requestInitialized method on ServletRequestListener org.jboss.weld.servlet.WeldListener
java.lang.IllegalStateException: Unable to load current conversations from the associated request, something went badly wrong when associate() was called
at org.jboss.weld.context.AbstractConversationContext.getCurrentConversation(AbstractConversationContext.java:393)
at org.jboss.weld.servlet.ConversationContextActivator.deactivateConversationContext(ConversationContextActivator.java:145)
at org.jboss.weld.servlet.WeldListener.requestDestroyed(WeldListener.java:152)
at org.jboss.weld.servlet.WeldListener.requestInitialized(WeldListener.java:205)
at org.apache.catalina.core.StandardContext.fireRequestInitializedEvent(StandardContext.java:5225)
at org.apache.catalina.core.StandardHostValve.preInvoke(StandardHostValve.java:647)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:166)
at org.apache.catalina.connector.CoyoteAdapter.doService(CoyoteAdapter.java:357)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:260)
at com.sun.enterprise.v3.services.impl.ContainerMapper.service(ContainerMapper.java:188)
at org.glassfish.grizzly.http.server.HttpHandler.runService(HttpHandler.java:191)
at org.glassfish.grizzly.http.server.HttpHandler.doHandle(HttpHandler.java:168)
at org.glassfish.grizzly.http.server.HttpServerFilter.handleRead(HttpServerFilter.java:189)
at org.glassfish.grizzly.filterchain.ExecutorResolver$9.execute(ExecutorResolver.java:119)
at org.glassfish.grizzly.filterchain.DefaultFilterChain.executeFilter(DefaultFilterChain.java:288)
at org.glassfish.grizzly.filterchain.DefaultFilterChain.executeChainPart(DefaultFilterChain.java:206)
at org.glassfish.grizzly.filterchain.DefaultFilterChain.execute(DefaultFilterChain.java:136)
at org.glassfish.grizzly.filterchain.DefaultFilterChain.process(DefaultFilterChain.java:114)
at org.glassfish.grizzly.ProcessorExecutor.execute(ProcessorExecutor.java:77)
at org.glassfish.grizzly.nio.transport.TCPNIOTransport.fireIOEvent(TCPNIOTransport.java:838)
at org.glassfish.grizzly.strategies.AbstractIOStrategy.fireIOEvent(AbstractIOStrategy.java:113)
at org.glassfish.grizzly.strategies.WorkerThreadIOStrategy.run0(WorkerThreadIOStrategy.java:115)
at org.glassfish.grizzly.strategies.WorkerThreadIOStrategy.access$100(WorkerThreadIOStrategy.java:55)
at org.glassfish.grizzly.strategies.WorkerThreadIOStrategy$WorkerThreadRunnable.run(WorkerThreadIOStrategy.java:135)
at org.glassfish.grizzly.threadpool.AbstractThreadPool$Worker.doWork(AbstractThreadPool.java:564)
at org.glassfish.grizzly.threadpool.AbstractThreadPool$Worker.run(AbstractThreadPool.java:544)
at java.lang.Thread.run(Thread.java:722)
]]

[2013-07-11T12:14:55.713+0000] [glassfish 4.0] [SEVERE] [] [javax.enterprise.resource.webcontainer.jsf.application] [tid: _ThreadID=101 _ThreadName=http-listener-1(1)] [timeMillis: 1373544895713] [levelValue: 1000] [[
Error Rendering View[/welcome.xhtml]
java.lang.IllegalStateException: A request must be associated with the context in order to load the known conversations
at org.jboss.weld.context.AbstractConversationContext.getCurrentConversation(AbstractConversationContext.java:390)
at org.jboss.weld.jsf.ConversationAwareViewHandler.getActionURL(ConversationAwareViewHandler.java:102)
at com.sun.faces.application.view.MultiViewHandler.getBookmarkableURL(MultiViewHandler.java:405)
at javax.faces.application.ViewHandlerWrapper.getBookmarkableURL(ViewHandlerWrapper.java:272)
at org.jboss.weld.jsf.ConversationAwareViewHandler.getBookmarkableURL(ConversationAwareViewHandler.java:124)
at com.sun.faces.renderkit.html_basic.OutcomeTargetRenderer.getEncodedTargetURL(OutcomeTargetRenderer.java:194)
at com.sun.faces.renderkit.html_basic.OutcomeTargetLinkRenderer.renderAsActive(OutcomeTargetLinkRenderer.java:158)
at com.sun.faces.renderkit.html_basic.OutcomeTargetLinkRenderer.encodeBegin(OutcomeTargetLinkRenderer.java:96)
at javax.faces.component.UIComponentBase.encodeBegin(UIComponentBase.java:869)
at javax.faces.component.UIComponent.encodeAll(UIComponent.java:1854)
at javax.faces.component.UIComponent.encodeAll(UIComponent.java:1859)
at javax.faces.component.UIComponent.encodeAll(UIComponent.java:1859)
at com.sun.faces.application.view.FaceletViewHandlingStrategy.renderView(FaceletViewHandlingStrategy.java:443)
at com.sun.faces.application.view.MultiViewHandler.renderView(MultiViewHandler.java:131)
at javax.faces.application.ViewHandlerWrapper.renderView(ViewHandlerWrapper.java:337)
at com.sun.faces.lifecycle.RenderResponsePhase.execute(RenderResponsePhase.java:120)
at com.sun.faces.lifecycle.Phase.doPhase(Phase.java:101)
at com.sun.faces.lifecycle.LifecycleImpl.render(LifecycleImpl.java:219)
at javax.faces.webapp.FacesServlet.service(FacesServlet.java:647)
at org.apache.catalina.core.StandardWrapper.service(StandardWrapper.java:1682)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:344)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:214)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:256)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:214)
at org.glassfish.tyrus.servlet.TyrusServletFilter.doFilter(TyrusServletFilter.java:253)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:256)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:214)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:316)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:160)
at org.apache.catalina.core.StandardPipeline.doInvoke(StandardPipeline.java:734)
at org.apache.catalina.core.StandardPipeline.invoke(StandardPipeline.java:673)
at com.sun.enterprise.web.WebPipeline.invoke(WebPipeline.java:99)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:174)
at org.apache.catalina.connector.CoyoteAdapter.doService(CoyoteAdapter.java:357)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:260)
at com.sun.enterprise.v3.services.impl.ContainerMapper.service(ContainerMapper.java:188)
at org.glassfish.grizzly.http.server.HttpHandler.runService(HttpHandler.java:191)
at org.glassfish.grizzly.http.server.HttpHandler.doHandle(HttpHandler.java:168)
at org.glassfish.grizzly.http.server.HttpServerFilter.handleRead(HttpServerFilter.java:189)
at org.glassfish.grizzly.filterchain.ExecutorResolver$9.execute(ExecutorResolver.java:119)
at org.glassfish.grizzly.filterchain.DefaultFilterChain.executeFilter(DefaultFilterChain.java:288)
at org.glassfish.grizzly.filterchain.DefaultFilterChain.executeChainPart(DefaultFilterChain.java:206)
at org.glassfish.grizzly.filterchain.DefaultFilterChain.execute(DefaultFilterChain.java:136)
at org.glassfish.grizzly.filterchain.DefaultFilterChain.process(DefaultFilterChain.java:114)
at org.glassfish.grizzly.ProcessorExecutor.execute(ProcessorExecutor.java:77)
at org.glassfish.grizzly.nio.transport.TCPNIOTransport.fireIOEvent(TCPNIOTransport.java:838)
at org.glassfish.grizzly.strategies.AbstractIOStrategy.fireIOEvent(AbstractIOStrategy.java:113)
at org.glassfish.grizzly.strategies.WorkerThreadIOStrategy.run0(WorkerThreadIOStrategy.java:115)
at org.glassfish.grizzly.strategies.WorkerThreadIOStrategy.access$100(WorkerThreadIOStrategy.java:55)
at org.glassfish.grizzly.strategies.WorkerThreadIOStrategy$WorkerThreadRunnable.run(WorkerThreadIOStrategy.java:135)
at org.glassfish.grizzly.threadpool.AbstractThreadPool$Worker.doWork(AbstractThreadPool.java:564)
at org.glassfish.grizzly.threadpool.AbstractThreadPool$Worker.run(AbstractThreadPool.java:544)
at java.lang.Thread.run(Thread.java:722)
]]

[2013-07-11T12:14:55.713+0000] [glassfish 4.0] [WARNING] [] [javax.enterprise.web] [tid: _ThreadID=101 _ThreadName=http-listener-1(1)] [timeMillis: 1373544895713] [levelValue: 900] [[
StandardWrapperValve[Faces Servlet]: Servlet.service() for servlet Faces Servlet threw exception
java.lang.IllegalStateException: A request must be associated with the context in order to load the known conversations
at org.jboss.weld.context.AbstractConversationContext.getCurrentConversation(AbstractConversationContext.java:390)
at org.jboss.weld.jsf.ConversationAwareViewHandler.getActionURL(ConversationAwareViewHandler.java:102)
at com.sun.faces.application.view.MultiViewHandler.getBookmarkableURL(MultiViewHandler.java:405)
at javax.faces.application.ViewHandlerWrapper.getBookmarkableURL(ViewHandlerWrapper.java:272)
at org.jboss.weld.jsf.ConversationAwareViewHandler.getBookmarkableURL(ConversationAwareViewHandler.java:124)
at com.sun.faces.renderkit.html_basic.OutcomeTargetRenderer.getEncodedTargetURL(OutcomeTargetRenderer.java:194)
at com.sun.faces.renderkit.html_basic.OutcomeTargetLinkRenderer.renderAsActive(OutcomeTargetLinkRenderer.java:158)
at com.sun.faces.renderkit.html_basic.OutcomeTargetLinkRenderer.encodeBegin(OutcomeTargetLinkRenderer.java:96)
at javax.faces.component.UIComponentBase.encodeBegin(UIComponentBase.java:869)
at javax.faces.component.UIComponent.encodeAll(UIComponent.java:1854)
at javax.faces.component.UIComponent.encodeAll(UIComponent.java:1859)
at javax.faces.component.UIComponent.encodeAll(UIComponent.java:1859)
at com.sun.faces.application.view.FaceletViewHandlingStrategy.renderView(FaceletViewHandlingStrategy.java:443)
at com.sun.faces.application.view.MultiViewHandler.renderView(MultiViewHandler.java:131)
at javax.faces.application.ViewHandlerWrapper.renderView(ViewHandlerWrapper.java:337)
at com.sun.faces.lifecycle.RenderResponsePhase.execute(RenderResponsePhase.java:120)
at com.sun.faces.lifecycle.Phase.doPhase(Phase.java:101)
at com.sun.faces.lifecycle.LifecycleImpl.render(LifecycleImpl.java:219)
at javax.faces.webapp.FacesServlet.service(FacesServlet.java:647)
at org.apache.catalina.core.StandardWrapper.service(StandardWrapper.java:1682)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:344)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:214)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:256)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:214)
at org.glassfish.tyrus.servlet.TyrusServletFilter.doFilter(TyrusServletFilter.java:253)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:256)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:214)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:316)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:160)
at org.apache.catalina.core.StandardPipeline.doInvoke(StandardPipeline.java:734)
at org.apache.catalina.core.StandardPipeline.invoke(StandardPipeline.java:673)
at com.sun.enterprise.web.WebPipeline.invoke(WebPipeline.java:99)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:174)
at org.apache.catalina.connector.CoyoteAdapter.doService(CoyoteAdapter.java:357)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:260)
at com.sun.enterprise.v3.services.impl.ContainerMapper.service(ContainerMapper.java:188)
at org.glassfish.grizzly.http.server.HttpHandler.runService(HttpHandler.java:191)
at org.glassfish.grizzly.http.server.HttpHandler.doHandle(HttpHandler.java:168)
at org.glassfish.grizzly.http.server.HttpServerFilter.handleRead(HttpServerFilter.java:189)
at org.glassfish.grizzly.filterchain.ExecutorResolver$9.execute(ExecutorResolver.java:119)
at org.glassfish.grizzly.filterchain.DefaultFilterChain.executeFilter(DefaultFilterChain.java:288)
at org.glassfish.grizzly.filterchain.DefaultFilterChain.executeChainPart(DefaultFilterChain.java:206)
at org.glassfish.grizzly.filterchain.DefaultFilterChain.execute(DefaultFilterChain.java:136)
at org.glassfish.grizzly.filterchain.DefaultFilterChain.process(DefaultFilterChain.java:114)
at org.glassfish.grizzly.ProcessorExecutor.execute(ProcessorExecutor.java:77)
at org.glassfish.grizzly.nio.transport.TCPNIOTransport.fireIOEvent(TCPNIOTransport.java:838)
at org.glassfish.grizzly.strategies.AbstractIOStrategy.fireIOEvent(AbstractIOStrategy.java:113)
at org.glassfish.grizzly.strategies.WorkerThreadIOStrategy.run0(WorkerThreadIOStrategy.java:115)
at org.glassfish.grizzly.strategies.WorkerThreadIOStrategy.access$100(WorkerThreadIOStrategy.java:55)
at org.glassfish.grizzly.strategies.WorkerThreadIOStrategy$WorkerThreadRunnable.run(WorkerThreadIOStrategy.java:135)
at org.glassfish.grizzly.threadpool.AbstractThreadPool$Worker.doWork(AbstractThreadPool.java:564)
at org.glassfish.grizzly.threadpool.AbstractThreadPool$Worker.run(AbstractThreadPool.java:544)
at java.lang.Thread.run(Thread.java:722)
]]

[2013-07-11T12:14:55.728+0000] [glassfish 4.0] [WARNING] [] [javax.enterprise.web.core] [tid: _ThreadID=101 _ThreadName=http-listener-1(1)] [timeMillis: 1373544895728] [levelValue: 900] [[
Error invoking requestDestroyed method on ServletRequestListener org.jboss.weld.servlet.WeldListener
java.lang.NullPointerException
at org.jboss.weld.context.AbstractBoundContext.deactivate(AbstractBoundContext.java:71)
at org.jboss.weld.context.http.HttpRequestContextImpl.deactivate(HttpRequestContextImpl.java:70)
at org.jboss.weld.servlet.WeldListener.requestDestroyed(WeldListener.java:154)
at org.apache.catalina.core.StandardContext.fireRequestDestroyedEvent(StandardContext.java:5261)
at org.apache.catalina.core.StandardHostValve.postInvoke(StandardHostValve.java:255)
at org.apache.catalina.connector.CoyoteAdapter.doService(CoyoteAdapter.java:359)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:260)
at com.sun.enterprise.v3.services.impl.ContainerMapper.service(ContainerMapper.java:188)
at org.glassfish.grizzly.http.server.HttpHandler.runService(HttpHandler.java:191)
at org.glassfish.grizzly.http.server.HttpHandler.doHandle(HttpHandler.java:168)
at org.glassfish.grizzly.http.server.HttpServerFilter.handleRead(HttpServerFilter.java:189)
at org.glassfish.grizzly.filterchain.ExecutorResolver$9.execute(ExecutorResolver.java:119)
at org.glassfish.grizzly.filterchain.DefaultFilterChain.executeFilter(DefaultFilterChain.java:288)
at org.glassfish.grizzly.filterchain.DefaultFilterChain.executeChainPart(DefaultFilterChain.java:206)
at org.glassfish.grizzly.filterchain.DefaultFilterChain.execute(DefaultFilterChain.java:136)
at org.glassfish.grizzly.filterchain.DefaultFilterChain.process(DefaultFilterChain.java:114)
at org.glassfish.grizzly.ProcessorExecutor.execute(ProcessorExecutor.java:77)
at org.glassfish.grizzly.nio.transport.TCPNIOTransport.fireIOEvent(TCPNIOTransport.java:838)
at org.glassfish.grizzly.strategies.AbstractIOStrategy.fireIOEvent(AbstractIOStrategy.java:113)
at org.glassfish.grizzly.strategies.WorkerThreadIOStrategy.run0(WorkerThreadIOStrategy.java:115)
at org.glassfish.grizzly.strategies.WorkerThreadIOStrategy.access$100(WorkerThreadIOStrategy.java:55)
at org.glassfish.grizzly.strategies.WorkerThreadIOStrategy$WorkerThreadRunnable.run(WorkerThreadIOStrategy.java:135)
at org.glassfish.grizzly.threadpool.AbstractThreadPool$Worker.doWork(AbstractThreadPool.java:564)
at org.glassfish.grizzly.threadpool.AbstractThreadPool$Worker.run(AbstractThreadPool.java:544)
at java.lang.Thread.run(Thread.java:722)
]]



 Comments   
Comment by Pavel Bucek [ 11/Jul/13 ]

already fixed in Tyrus 1.1, duplicate of TYRUS-192





[SERVLET_SPEC-74] HttpServletResponse#sendRedirect(String) could use some improvement; needs 301/302/303 support; needs way to set request body Created: 25/May/13  Updated: 07/Aug/14

Status: Open
Project: servlet-spec
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Improvement Priority: Major
Reporter: Nick Williams Assignee: Shing Wai Chan
Resolution: Unresolved Votes: 1
Labels: None
Remaining Estimate: 1 day
Time Spent: Not Specified
Original Estimate: 1 day

Issue Links:
Related
is related to SERVLET_SPEC-100 sendRedirect permanent vs temporary a... Open
Tags: 301, 302, 303, get, http, permanent, redirect, response

 Description   

Currently, HttpServletResponse#sendRedirect(String) specifies the following hard-wired behavior that cannot be changed:

  • Send the redirect using status code 302 Found and the Location header.
  • Clear the buffer and set the response body to a short hypertext note with a hyperlink to the new URI.

I have three issues with this behavior that I summarize below, and at the bottom I propose a solution:

Issue 1

RFC 2616, says the following about 302 Found:

If the 302 status code is received in response to a request other than GET or HEAD, the user agent MUST NOT automatically redirect the request unless it can be confirmed by the user, since this might change the conditions under which the request was issued.

Note: RFC 1945 and RFC 2068 specify that the client is not allowed to change the method on the redirected request. However, most existing user agent implementations treat 302 as if it were a 303 response, performing a GET on the Location field-value regardless of the original request method.

The two keys here are 1) that the spec says browsers MUST NOT automatically redirect the request and 2) that there could be some browsers that send the second request with the original method (POST, PUT, etc.).

As an application not concerned with legacy HTTP/1.0 user-agents and more concerned with ensuring that user agents do not prompt the user for permission to redirect and do not redirect using a POST or a PUT, etc., I prefer to use the 303 See Other response as opposed to the 302 Found response:

The response to the request can be found under a different URI and SHOULD be retrieved using a GET method on that resource. This method exists primarily to allow the output of a POST-activated script to redirect the user agent to a selected resource. ... The 303 response MUST NOT be cached, but the response to the second (redirected) request might be cacheable.

Issue 2

As an application that has recently been refactored, I want to be able to easily send a permanent redirect to users for old URLs that have been removed and should be changed. This can be achieved with the 301 Moved Permanently response:

The requested resource has been assigned a new permanent URI and any future references to this resource SHOULD use one of the returned URIs. Clients with link editing capabilities ought to automatically re-link references to the Request-URI to one or more of the new references returned by the server, where possible. ... The new permanent URI SHOULD be given by the Location field in the response. Unless the request method was HEAD, the entity of the response SHOULD contain a short hypertext note with a hyperlink to the new URI(s). ... If the 301 status code is received in response to a request other than GET or HEAD, the user agent MUST NOT automatically redirect the request unless it can be confirmed by the user, since this might change the conditions under which the request was issued.

Issue 3

The exact wording of the short hypertext response included with the current 302 Found responses is not consistent across containers. As an application developer that cares about branding and consistency, I would like to be able to customize this text within my code and do so in a way that is consistent across all containers.

Recommendation

I believe the following additions to the Servlet API will greatly improve the current HttpServletResponse#sendRedirect(String) and satisfy the needs outlined here.

New HttpRedirectType Enum
public enum HttpRedirectType {
    /*
     * Indicates that the {@code 301 Moved Permanently} status should be used.
     * Could alternatively be called MOVED_PERMANENTLY.
     */
    PERMANENT,

    /*
     * Indicates that the {@code 302 Found} status should be used.
     * Could alternatively be called FOUND.
     */
    TEMPORARY_SAME_METHOD,

    /*
     * Indicates that the {@code 303 See Other} status should be used.
     * Could alternatively be called SEE_OTHER.
     */
    TEMPORARY_USE_GET;
}
Additions to HttpServletResponse
public interface HttpServletResponse {
...
    void sendRedirect(String location, HttpRedirectType type);

    void sendRedirect(String location, boolean replaceBuffer);

    void sendRedirect(String location, HttpRedirectType type, boolean replaceBuffer);
...
}
  • If replaceBuffer is true, the container should clear the buffer and replace it with the data set by this method. If replaceBuffer is false, the container should send the existing buffer and should not add to it (even if it is empty) or remove from it.
  • The existing sendRedirect(String) should call sendRedirect(location, HttpRedirectType.TEMPORARY_SAME_METHOD, true) to preserve current behavior.
  • The new sendRedirect(String, HttpRedirectType) should call sendRedirect(location, type, true) to use the default response body.
  • The new sendRedirect(String, boolean) should call sendRedirect(location, HttpRedirectType.TEMPORARY_SAME_METHOD, replaceBuffer) to use the default 302 Found response.





[OPENPTK-301] Authorization check Created: 30/Nov/11  Updated: 30/Nov/11

Status: Open
Project: openptk
Component/s: Server
Affects Version/s: None
Fix Version/s: None

Type: New Feature Priority: Minor
Reporter: Scott Fehrman Assignee: Scott Fehrman
Resolution: Unresolved Votes: 0
Labels: None
Remaining Estimate: Not Specified
Time Spent: Not Specified
Original Estimate: Not Specified

Tags: authorization, head, headers, http

 Description   

Implement a mechanism where the client can perform an authorization check against the combination of a given URI and its HTTP Operation. The client can use this mechanism to determine if the "actual" HTTP Operation / URI would be allowed or denied.

Considerations:

  • Use the HTTP HEAD Operation (with HTTP Header variables) to indicate the HTTP Request is an "authorization check"
  • Use query parameter to indicate the HTTP Request is an "authorization check". Necessary for clients / firewalls / servers that do not support the HTTP HEAD Operation


 Comments   
Comment by Scott Fehrman [ 30/Nov/11 ]

Create a "project" page to document requirements, architecture and design

https://sites.google.com/a/openptk.org/docs/projects/authorization-check





[OPENPTK-300] Support data type declaration via URI Created: 30/Nov/11  Updated: 23/Apr/12  Resolved: 22/Apr/12

Status: Closed
Project: openptk
Component/s: Server
Affects Version/s: 2.1
Fix Version/s: 2.1

Type: New Feature Priority: Trivial
Reporter: Scott Fehrman Assignee: Scott Fehrman
Resolution: Fixed Votes: 1
Labels: None
Remaining Estimate: Not Specified
Time Spent: Not Specified
Original Estimate: Not Specified

Issue Links:
Dependency
blocks OPENPTK-283 Implement SCIM 1.0 server interface Open
Tags: header, http, json, rest, restful, uri, xml

 Description   

Enhance the RESTful service to support the declaration of the data type via a URI suffix.

This feature would provide an alternative to using HTTP Header variables. This is required for clients that can not support HTTP Header variables. In this case, the data type is set through the use of a URI suffix: .json or .xml

GET Example:

The HTTP Response data would be formatted using the specific suffix.

curl http://server/openptk/contexts/devel/subjects/ja1324.json
curl http://server/openptk/contexts/devel/subjects/ja1324.xml

POST Example:

The HTTP Request data (payload) would be formatted with the specific suffix.

curl -X POST http://server/openptk/devel/embedded/subjects.json
curl -X POST http://server/openptk/devel/embedded/subjects.xml

PUT Example:

The HTTP Request data (payload) would be formatted with the specific suffix.

curl -X PUT http://server/openptk/contexts/devel/subjects/ja1324.json
curl -X PUT http://server/openptk/contexts/devel/subjects/ja1324.xml

If an HTTP Request contains a valid HTTP Header (Accept: or Content-Type:) AND a valid URI suffix, the suffix will take precedence over the Header variable.



 Comments   
Comment by jkimble2 [ 13/Jan/12 ]

This would be a big help with Adobe Flex integration.

Flex does not allow GET operations to have custom header values and the default Accept var cause html return values. Having this would allow the return type to be forced to XML or JSON.

example Flex GET request header:

GET /openptk-server/resources/contexts/User-Oracle-OIMClient/subjects/?search=j1234 HTTP/1.1
Host: host.com
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.7; rv:9.0.1) Gecko/20100101 Firefox/9.0.1
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-us,en;q=0.5
Accept-Encoding: gzip, deflate
Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7
Cookie: JSESSIONID=1SQbPPwhfvZyC0qx23XTZ6zvQ8QQ0pmsSBpfh8T1XHPp1Z9X6FhW!321005851; OPENPTKSESSIONID=e6998d4a-8b05-4154-8fc7-5d144f09d9ef
Comment by Scott Fehrman [ 17/Jan/12 ]

Creating a prototype solution based on a Servlet Filter. The filter would be configured before the Authen Servlet Filter.

This filter will check for one of the supported suffixes: .xml, .json, .html, .plain. If one is used in the URL, the filter will remove the suffix from the request an d it will set / replace the Headers for content-type or accept.

Comment by Scott Fehrman [ 29/Jan/12 ]

Changed solution to use a Query Parameter (format) instead of a suffix string

GET Example:

The HTTP Response data would be formatted using the specified format.

curl http://server/openptk/contexts/devel/subjects/ja1324?format=json
curl http://server/openptk/contexts/devel/subjects/ja1324?format=xml

POST Example:

The HTTP Request data (payload) would be formatted with the specified format.

curl -X POST http://server/openptk/devel/embedded/subjects?format=json
curl -X POST http://server/openptk/devel/embedded/subjects?format=xml

PUT Example:

The HTTP Request data (payload) would be formatted with the specified format.

curl -X PUT http://server/openptk/contexts/devel/subjects/ja1324?format=json
curl -X PUT http://server/openptk/contexts/devel/subjects/ja1324?format=xml
Comment by Scott Fehrman [ 14/Feb/12 ]

Created an implementation of the UriConnegFilter class to convert the suffix to the header variable.
http://jersey.java.net/nonav/apidocs/1.11/jersey/com/sun/jersey/api/container/filter/UriConnegFilter.html

But this only seems to work with the GET method ....

package org.openptk.jaxrs.filter;

import java.util.HashMap;
import java.util.Map;
import javax.ws.rs.core.MediaType;
import com.sun.jersey.api.container.filter.UriConnegFilter;

public class SuffixFilter extends UriConnegFilter
{

   private static final Map<String, MediaType> mapMedia = new HashMap<String, MediaType>(4);

   static
   {
      mapMedia.put("xml", MediaType.APPLICATION_XML_TYPE);
      mapMedia.put("json", MediaType.APPLICATION_JSON_TYPE);
      mapMedia.put("html", MediaType.TEXT_HTML_TYPE);
      mapMedia.put("plain", MediaType.TEXT_PLAIN_TYPE);
   }

   public SuffixFilter()
   {
      super(mapMedia);

      return;
   }
}

This technique does not work on the top level of the @Path name. The authorization mechanism in the servlet filter does not properly handle the suffix naming.

The query parameter support was added to the Resource class which implements the Jersey servlet. But this also only works for the GET method.

Will purse a standalone ServletFilter design. This design should support GET, POST, PUT and DELETE. This MimeTypeHeaderFilter will be configured before the authen filter so both the suffix and query parameter techniques should be converted to Header variables.

Comment by Scott Fehrman [ 18/Feb/12 ]

Checked in solution using a custom Servlet Filter MimeTypeHeaderFilter.java and a custom RequestWrapper MimeTypeHeaderRequestWrapper.java

The Filter support the following alternatives to using Header Variables for the mime-type:

  • Query Parameter
  • URI Suffix
  • Both

The web.xml has been updated to support the filter. The filter is disabled by default. An init-param must be set to enable it. See the project web page for details: http://docs.openptk.org/projects/restful-hdr-var-mime-type-alt

Comment by Scott Fehrman [ 29/Mar/12 ]

Implemented support for POST and PUT HTTP request types

Comment by Scott Fehrman [ 04/Apr/12 ]

Initial testing completed. Created test cases on the Project page: https://sites.google.com/a/openptk.org/docs/projects/restful-hdr-var-mime-type-alt

Tests support both the "suffix" and "parameter" options.

The installation page:
https://sites.google.com/a/openptk.org/docs/release-2-x/install/21-mimetype-via-uri

Comment by harcey [ 22/Apr/12 ]

Testing completed for states:

disabled, both, parameter and suffix.

All test cases worked as expected, however, one scenario lead to a null pointer exception and an internal server error, that should be resolved, reopening issue with details of the scenario.

Comment by harcey [ 22/Apr/12 ]

Reopening issue due to nullpointer exception.

This scenario was when the server was in suffix mode and the following test was run:

$ curl -X POST -v -b cookies.txt -d '{"subject" : { "attributes" : { "lastname" : "Bauer", "title" : "Agent", "firstname" : "Jack", "telephone" : "123-456-7890", "email" : "jack@ctu.gov" }}}' http://localhost:8080/openptk-server/resources/contexts/Employees-Embed-JDBC/subjects\?format=json
* About to connect() to localhost port 8080 (#0)
*   Trying ::1... connected
* Connected to localhost (::1) port 8080 (#0)
> POST /openptk-server/resources/contexts/Employees-Embed-JDBC/subjects?format=json HTTP/1.1
> User-Agent: curl/7.21.4 (universal-apple-darwin11.0) libcurl/7.21.4 OpenSSL/0.9.8r zlib/1.2.5
> Host: localhost:8080
> Accept: */*
> Cookie: JSESSIONID=7e3785c17371178db92cf67d10cb; OPENPTKSESSIONID=3c61009d-0f2d-49c6-b442-5e6d521a6fa3
> Content-Length: 153
> Content-Type: application/x-www-form-urlencoded
> 
< HTTP/1.1 500 Internal Server Error
< Content-Type: text/html
< Content-Length: 1337
< Date: Sun, 22 Apr 2012 02:33:23 GMT
< Connection: close
< 
* Closing connection #0
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"><html xmlns="http://www.w3.org/1999/xhtml"><head><title>GlassFish Server Open Source Edition 3.1.1 - Error report</title><style type="text/css"><!--H1 {font-family:Tahoma,Arial,sans-serif;color:white;background-color:#525D76;font-size:22px;} H2 {font-family:Tahoma,Arial,sans-serif;color:white;background-color:#525D76;font-size:16px;} H3 {font-family:Tahoma,Arial,sans-serif;color:white;background-color:#525D76;font-size:14px;} BODY {font-family:Tahoma,Arial,sans-serif;color:black;background-color:white;} B {font-family:Tahoma,Arial,sans-serif;color:white;background-color:#525D76;} P {font-family:Tahoma,Arial,sans-serif;background:white;color:black;font-size:12px;}A {color : black;}HR {color : #525D76;}--></style> </head><body><h1>HTTP Status 500 - </h1><hr/><p><b>type</b> Exception report</p><p><b>message</b></p><p><b>description</b>The server encountered an internal error () that prevented it from fulfilling this request.</p><p><b>exception</b> <pre>java.lang.NullPointerException</pre></p><p><b>note</b> <u>The full stack traces of the exception and its root causes are available in the GlassFish Server Open Source Edition 3.1.1 logs.</u></p><hr/><h3>GlassFish Server Open Source Edition 3.1.1</h3></body></html>Derricks-MacBook

The following server logs error was found:

WARNING: StandardWrapperValve[ServletAdaptor]: PWC1406: Servlet.service() for servlet ServletAdaptor threw exception
java.lang.NullPointerException
	at java.util.Arrays$ArrayList.<init>(Arrays.java:3357)
	at java.util.Arrays.asList(Arrays.java:3343)
	at com.sun.jersey.spi.container.servlet.WebComponent.filterFormParameters(WebComponent.java:840)
	at com.sun.jersey.spi.container.servlet.WebComponent.service(WebComponent.java:405)
	at com.sun.jersey.spi.container.servlet.ServletContainer.service(ServletContainer.java:537)
	at com.sun.jersey.spi.container.servlet.ServletContainer.service(ServletContainer.java:708)
	at javax.servlet.http.HttpServlet.service(HttpServlet.java:847)
	at org.apache.catalina.core.StandardWrapper.service(StandardWrapper.java:1539)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:343)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:217)
	at org.openptk.servlet.filters.ServerAuthFilter.doFilter(ServerAuthFilter.java:618)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:256)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:217)
	at org.openptk.servlet.filters.MimeTypeHeaderFilter.doFilter(MimeTypeHeaderFilter.java:134)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:256)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:217)
	at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:279)
	at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:175)
	at org.apache.catalina.core.StandardPipeline.doInvoke(StandardPipeline.java:655)
	at org.apache.catalina.core.StandardPipeline.invoke(StandardPipeline.java:595)
	at com.sun.enterprise.web.WebPipeline.invoke(WebPipeline.java:98)
	at com.sun.enterprise.web.PESessionLockingStandardPipeline.invoke(PESessionLockingStandardPipeline.java:91)
	at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:162)
	at org.apache.catalina.connector.CoyoteAdapter.doService(CoyoteAdapter.java:330)
	at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:231)
	at com.sun.enterprise.v3.services.impl.ContainerMapper.service(ContainerMapper.java:174)
	at com.sun.grizzly.http.ProcessorTask.invokeAdapter(ProcessorTask.java:828)
	at com.sun.grizzly.http.ProcessorTask.doProcess(ProcessorTask.java:725)
	at com.sun.grizzly.http.ProcessorTask.process(ProcessorTask.java:1019)
	at com.sun.grizzly.http.DefaultProtocolFilter.execute(DefaultProtocolFilter.java:225)
	at com.sun.grizzly.DefaultProtocolChain.executeProtocolFilter(DefaultProtocolChain.java:137)
	at com.sun.grizzly.DefaultProtocolChain.execute(DefaultProtocolChain.java:104)
	at com.sun.grizzly.DefaultProtocolChain.execute(DefaultProtocolChain.java:90)
	at com.sun.grizzly.http.HttpProtocolChain.execute(HttpProtocolChain.java:79)
	at com.sun.grizzly.ProtocolChainContextTask.doCall(ProtocolChainContextTask.java:54)
	at com.sun.grizzly.SelectionKeyContextTask.call(SelectionKeyContextTask.java:59)
	at com.sun.grizzly.ContextTask.run(ContextTask.java:71)
	at com.sun.grizzly.util.AbstractThreadPool$Worker.doWork(AbstractThreadPool.java:532)
	at com.sun.grizzly.util.AbstractThreadPool$Worker.run(AbstractThreadPool.java:513)
	at java.lang.Thread.run(Thread.java:680)

WARNING: StandardWrapperValve[ServletAdaptor]: PWC1406: Servlet.service() for servlet ServletAdaptor threw exception
java.lang.NullPointerException
	at java.util.Arrays$ArrayList.<init>(Arrays.java:3357)
	at java.util.Arrays.asList(Arrays.java:3343)
	at com.sun.jersey.spi.container.servlet.WebComponent.filterFormParameters(WebComponent.java:840)
	at com.sun.jersey.spi.container.servlet.WebComponent.service(WebComponent.java:405)
	at com.sun.jersey.spi.container.servlet.ServletContainer.service(ServletContainer.java:537)
	at com.sun.jersey.spi.container.servlet.ServletContainer.service(ServletContainer.java:708)
	at javax.servlet.http.HttpServlet.service(HttpServlet.java:847)
	at org.apache.catalina.core.StandardWrapper.service(StandardWrapper.java:1539)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:343)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:217)
	at org.openptk.servlet.filters.ServerAuthFilter.doFilter(ServerAuthFilter.java:618)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:256)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:217)
	at org.openptk.servlet.filters.MimeTypeHeaderFilter.doFilter(MimeTypeHeaderFilter.java:134)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:256)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:217)
	at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:279)
	at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:175)
	at org.apache.catalina.core.StandardPipeline.doInvoke(StandardPipeline.java:655)
	at org.apache.catalina.core.StandardPipeline.invoke(StandardPipeline.java:595)
	at com.sun.enterprise.web.WebPipeline.invoke(WebPipeline.java:98)
	at com.sun.enterprise.web.PESessionLockingStandardPipeline.invoke(PESessionLockingStandardPipeline.java:91)
	at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:162)
	at org.apache.catalina.connector.CoyoteAdapter.doService(CoyoteAdapter.java:330)
	at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:231)
	at com.sun.enterprise.v3.services.impl.ContainerMapper.service(ContainerMapper.java:174)
	at com.sun.grizzly.http.ProcessorTask.invokeAdapter(ProcessorTask.java:828)
	at com.sun.grizzly.http.ProcessorTask.doProcess(ProcessorTask.java:725)
	at com.sun.grizzly.http.ProcessorTask.process(ProcessorTask.java:1019)
	at com.sun.grizzly.http.DefaultProtocolFilter.execute(DefaultProtocolFilter.java:225)
	at com.sun.grizzly.DefaultProtocolChain.executeProtocolFilter(DefaultProtocolChain.java:137)
	at com.sun.grizzly.DefaultProtocolChain.execute(DefaultProtocolChain.java:104)
	at com.sun.grizzly.DefaultProtocolChain.execute(DefaultProtocolChain.java:90)
	at com.sun.grizzly.http.HttpProtocolChain.execute(HttpProtocolChain.java:79)
	at com.sun.grizzly.ProtocolChainContextTask.doCall(ProtocolChainContextTask.java:54)
	at com.sun.grizzly.SelectionKeyContextTask.call(SelectionKeyContextTask.java:59)
	at com.sun.grizzly.ContextTask.run(ContextTask.java:71)
	at com.sun.grizzly.util.AbstractThreadPool$Worker.doWork(AbstractThreadPool.java:532)
	at com.sun.grizzly.util.AbstractThreadPool$Worker.run(AbstractThreadPool.java:513)
	at java.lang.Thread.run(Thread.java:680)
Comment by Scott Fehrman [ 22/Apr/12 ]

fixed null pointer condition ... output from test scenario, proper error is returned: 415 Unsupported Media Type

ServletFilter mode is "suffix"

curl -X POST -v -b cookies.txt -d '{"subject" : { "attributes" : { "lastname" : "Bauer", "title" : "Agent", "firstname" : "Jack", "telephone" : "123-456-7890", "email" : "jack@ctu.gov" }}}' http://localhost:8080/openptk-server/resources/contexts/Employees-Embed-JDBC/subjects\?format=json
* About to connect() to localhost port 8080 (#0)
*   Trying ::1... connected
* Connected to localhost (::1) port 8080 (#0)
> POST /openptk-server/resources/contexts/Employees-Embed-JDBC/subjects?format=json HTTP/1.1
> User-Agent: curl/7.21.4 (universal-apple-darwin11.0) libcurl/7.21.4 OpenSSL/0.9.8r zlib/1.2.5
> Host: localhost:8080
> Accept: */*
> Cookie: JSESSIONID=c21a29e2bf5bf0c72e4ce220e10a; OPENPTKSESSIONID=efb5631e-6d13-47c8-b33c-ff255b12fd78
> Content-Length: 153
> Content-Type: application/x-www-form-urlencoded
> 
< HTTP/1.1 415 Unsupported Media Type
< X-Powered-By: Servlet/3.0 JSP/2.2 (GlassFish Server Open Source Edition 3.1.1 Java/Apple Inc./1.6)
< Server: GlassFish Server Open Source Edition 3.1.1
< Content-Type: text/html
< Content-Length: 1232
< Date: Sun, 22 Apr 2012 22:17:37 GMT
< 
* Connection #0 to host localhost left intact
* Closing connection #0
Comment by harcey [ 23/Apr/12 ]

Testing completed, closing issue





[OPENPTK-299] Overload HTTP POST to support other HTTP Request types Created: 29/Nov/11  Updated: 30/Nov/11

Status: Open
Project: openptk
Component/s: Server
Affects Version/s: None
Fix Version/s: None

Type: New Feature Priority: Minor
Reporter: Scott Fehrman Assignee: Scott Fehrman
Resolution: Unresolved Votes: 0
Labels: None
Remaining Estimate: Not Specified
Time Spent: Not Specified
Original Estimate: Not Specified

Issue Links:
Dependency
blocks OPENPTK-283 Implement SCIM 1.0 server interface Open
Tags: DELETE, HTTP, POST, PUT, RESTFUL

 Description   

Project OpenPTK, by default, supports the use of HTTP GET, POST, PUT and DELETE as part of it's RESTful Web Service interface.

There are situations where a deployment (firewall) may only allow HTTP GET and POST Requests. To support this type of configuration, it is suggested that the HTTP PUT and HTTP DELETE Requests by "tunneled" as HTTP POST Request. If the HTTP Request needs to be treated as either PUT or DELETE (instead of a POST), a "flag" would be provided by the client to indicate how to process the POST Request.

Some possible techniques for "indicating" either a PUT or DELETE include; adding a query parameter to the URL and/or leverage a Header variable. The use of a query parameter in the URL, operation=PUT, would be easy for non-Browser clients that may not be able to set Header variables (easily).

There should be an order of precedence for ultimately deciding what the Request should be handled:

  1. if the HTTP Request is POST ...
    1. a query parameter will be checked ... operation=PUT
    2. a header variable will be checked ... OPENPTKOPERATION=PUT
  2. else the Request will be processed as a POST

If a Header variable and a query parameter are set ... they are processed in the order listed above. The system will use the first one (query parameter or header) that is found.



 Comments   
Comment by Scott Fehrman [ 30/Nov/11 ]

Recommended HTTP Header variable name: X-HTTP-Method-Override

PUT

X-HTTP-Method-Override: PUT

DELETE

X-HTTP-Method-Override: DELETE




[OPENPTK-281] ServerAuthFilter doesn't use cookie from request headers Created: 21/Jul/11  Updated: 23/Aug/11  Resolved: 31/Jul/11

Status: Closed
Project: openptk
Component/s: Framework
Affects Version/s: 2.0
Fix Version/s: 2.0

Type: Bug Priority: Major
Reporter: pkulka2011 Assignee: harcey
Resolution: Fixed Votes: 0
Labels: None
Remaining Estimate: Not Specified
Time Spent: Not Specified
Original Estimate: Not Specified

Tags: cookies, header, http, request

 Description   

I'm seeing different cookie handling behavior in the latest version of PTK code. The cookies from requests are taken from request.cookie class , the cookie from request headers are ignored.

We used F5 to load balance PTK managed servers (2 of them) for the clients and we use cookie persistence on the LB. However we see the requests to PTK fails if the OPENPTKSESSIONID cookie doesn't exists in request.cookie object, however it exists in request headers but its ignored.

What do you recommend we do in this case? Please compare the log sections in blue in the two sections below to see the difference in behavior. Obviously the load balancer is stripping off the OPENPTKSESSIONID cookie and we're working on that right now but meanwhile I wanted to check with you.

Logs without load balancer

INFO: 2011-07-21 09:24:45.488 CDT: ServerAuthFilter:requestInfo(): GET
contextPath='/openptk-server' 
requestURI='/openptk-server/resources/clients/niiopenptkclientid' 
requestURL='http://10.103.74.33:7777/openptk-server/resources/clients/niiopenptkclientid' 
servletPath='/resources' 
pathInfo='/clients/niiopenptkclientid' 
queryString='' 
remoteUser='' 
requestedSessionId='f59PTy2NJb7kfNMPGL5h8M2YvQ0p9Ky3LSLY1ptV5vz0BLVVZFBf!1029462724' 
sessionId='Q81YTy2N8lVyQqBJBMCKYBsn5k10QqNGDjySlBSTpGyGVvcyjjJH!-364943042!1311258285488' 
Cookies=[ 
   OPENPTKSESSIONID='862819a1-c10b-4a2f-a71a-a9a9a71d7b61' 
] 
Attributes=[ ] 
Headers=[ 
   Cookie='OPENPTKSESSIONID=862819a1-c10b-4a2f-a71a-a9a9a71d7b61;Version=1,JSESSIONID=f59PTy2NJb7kfNMPGL5h8M2YvQ0p9Ky3LSLY1ptV5vz0BLVVZFBf!1029462724;Version=1' 
   Content-Type='application/xml' 
   Accept='application/xml' 
   User-Agent='Java1.6.0_14' 
   Host='10.103.74.33:7777' 
   ECID-   Context='1.004e9KSJg7y5qYDLnAw0yZ0005Zn0002cD;kXjE1ZDLIPJRjFOS_UOSoRPBnLQSqLQSj2TPnVPTmJPPnVBOgPPPiKVSjEPQdVOS_UOSoRROgPPPiKTQ^G' 
   Connection='Keep-Alive' 
   Proxy-Client-IP='10.12.105.70' 
   X-Forwarded-For='10.12.105.70' 
   X-WebLogic-KeepAliveSecs='25' 
   X-WebLogic-Request-ClusterInfo='true' 
   x-weblogic-cluster-hash='UaqZId+kDCPBINSMC1V/2f1crV8' 
] 
Parameters=[ ] 

Logs with Load Balancer

INFO: 2011-07-21 09:28:29.613 CDT: ServerAuthFilter:requestInfo(): GET 
contextPath='/openptk-server' 
requestURI='/openptk-server/resources/clients/niiopenptkclientid' 
requestURL='http://ptkuat.example.com.mx:80/openptk-server/resources/clients/niiopenptkclientid' 
servletPath='/resources' 
pathInfo='/clients/niiopenptkclientid' 
queryString='' 
remoteUser='' 
requestedSessionId='Mc2pTy3Nz1lSQYwnN7KmyJ5Kfx4Zb5JvCRGcQwCJFlQBDMFYKJTv!1029462724' 
sessionId='sPXKTy3N8LTWbxB8mJyp8LrmDBFyhh0HT6HkfmmZNYnG7Vm4bmrh!-364943042!1311258509612' 
Cookies=[ 
   BIGipServerPOOL_UAT_ptkuat.example.com.mx_80='558524170.24862.0000' 
] 
Attributes=[ ] 
Headers=[ 
   Cookie='BIGipServerPOOL_UAT_ptkuat.example.com.mx_80=558524170.24862.0000;Version=1,OPENPTKSESSIONID=94bbc7d0-19e1-42f1-8fef-88e8d26e0d5f;Version=1,JSESSIONID=Mc2pTy3Nz1lSQYwnN7KmyJ5Kfx4Zb5JvCRGcQwCJFlQBDMFYKJTv!1029462724;Version=1' 
   Content-Type='application/xml' 
   Accept='application/xml' 
   User-Agent='Java1.6.0_14' 
   Host='ptkuat.example.com.mx' 
   ECID-Context='1.004e9Kdf97w5qYDLnAw0yZ0005Zn0002dD;kXjE1ZDLIPJRjFOS_UOSoRPBnLQSqLQSj2TPnVPTmJPPnVBOgPPPiKVSjEPQdVOS_UOSoRROgPPPiKTQ^G' 
   Connection='Keep-Alive' 
   Proxy-Client-IP='10.103.74.100' 
   X-Forwarded-For='10.103.74.100' 
   X-WebLogic-KeepAliveSecs='25' 
   X-WebLogic-Request-ClusterInfo='true' 
   x-weblogic-cluster-hash='UaqZId+kDCPBINSMC1V/2f1crV8' 
] 
Parameters=[ ] 


 Comments   
Comment by Scott Fehrman [ 21/Jul/11 ]

set versions, tags

Comment by Scott Fehrman [ 23/Jul/11 ]

The log data is generated from the ServerAuthFilter (actually the AutherFilter abstract) class and it's
requestInfo() method. The data is obtain by "calling" a number of "get*" methods on the
HttpServletRequest (hrequest) Object. Here is how the "Cookie" data is obtained:

The hrequest has a method, getCookies(), which returns a Collection of Cookies associated with the
hrequest. Each Cookie in the Collection is processed ... the name (String) is obtained and then the
value (String) is obtained. The related Cookie name and value is added to the data buffer. Here is
the code (AuthFilter.java) ...

      buf.append("Cookies=[ ");
      cookies = hrequest.getCookies();
      if (cookies != null && cookies.length > 0)
      {
         for (Cookie cookie : cookies)
         {
            name = cookie.getName();
            if (name != null && name.length() > 0)
            {
               value = cookie.getValue();
               buf.append(name).append("='").append((value != null ? value : "")).append("' ");
            }
         }
      }
      buf.append("] ");

The hrequest has a method, getHeaderNames(), which return an Enumeration of header names.
Each name (String) in the enumeration is processed. For each name, the value (String) of the header
is obtained. The name related value for each hrequest header is added to the data buffer. Here is
the code (AuthFilter.java) ...

      buf.append("Headers=[ ");
      enumObj = hrequest.getHeaderNames();
      while (enumObj.hasMoreElements())
      {
         name = (String) enumObj.nextElement();
         if (name != null && name.length() > 0)
         {
            value = hrequest.getHeader(name);
            if (value != null && value.length() > 0
               && name.equalsIgnoreCase("password"))
            {
               value = this.mask(value);
            }
            buf.append(name).append("='").append((value != null ? value : "")).append("' ");
         }
      }
      buf.append("] ");

The management of Cookies is done through the use of the HttpServletRequest getCookies() method
and HttpServletResponse addCookie() method. HTTP Headers (name/value) are not being used or set.

In this situation, the Load Balancer is removing the Request Cookie ... which is required. The Header
data, specifically the "Cookie" data, does not appear to be touched. Again ... the Header data is not
an actual HTTP Cookie, it's a String encoded value that contains the String representation of one
(or more) Cookies. The AuthFilter does not use Header values.

Comment by harcey [ 31/Jul/11 ]

The Authentication Design (issue 28), has been resolved after the team addressed issues related to cookie diagnostics and prevention of redundant cookies in results.

All known authentication and cookie handling is working as expected in our testing.

Please update to the latest build and test again.

Comment by Scott Fehrman [ 23/Aug/11 ]

Issue has not been detected with closed authentication issue.





[LWUIT-426] LWUIT IO http redirection Created: 13/Apr/11  Updated: 17/Apr/11  Resolved: 17/Apr/11

Status: Resolved
Project: lwuit
Component/s: None
Affects Version/s: current
Fix Version/s: None

Type: Bug Priority: Major
Reporter: tempusername Assignee: Unassigned
Resolution: Fixed Votes: 0
Labels: None
Remaining Estimate: Not Specified
Time Spent: Not Specified
Original Estimate: Not Specified

Tags: HTTP, LWUITIO

 Description   

when a redirect response is sent from http server (301 or 302) and http arguments were already set
the following code is executed

if(followRedirects && (responseCode == 301 || responseCode == 302

responseCode == 303)) {
String uri = impl.getHeaderField("location", connection);

if(!(uri.startsWith("http://") || uri.startsWith("https://"))) {
// relative URI's in the location header are illegal but some sites mistakenly use them
url = Util.relativeToAbsolute(url, uri);
} else {
url = uri;
}
if((responseCode == 302 || responseCode == 303)){
setPost(false);
}

the problem is with setPost(false); line (which im not sure why it should be called at all - why not keep the current post settings)
inside the setPost method there is the following code
if(this.post != post && requestArguments != null && requestArguments.size() > 0) {
throw new IllegalStateException("Request method (post/get) can't be modified one arguments have been assigned to the request");
}
and since the arguments were set in the original request and were not reseted (nor do i think they should be reset) an exception is thrown thus preventing the redirection.



 Comments   
Comment by vprise [ 17/Apr/11 ]

Thanks, that does seem incorrect. I have no idea why that code is there.





[LWUIT-421] Need access to the HTTP response headers Created: 28/Mar/11  Updated: 03/Apr/11  Resolved: 03/Apr/11

Status: Resolved
Project: lwuit
Component/s: None
Affects Version/s: current
Fix Version/s: None

Type: Improvement Priority: Minor
Reporter: mahdi_hijazi Assignee: Unassigned
Resolution: Fixed Votes: 0
Labels: None
Remaining Estimate: Not Specified
Time Spent: Not Specified
Original Estimate: Not Specified

Tags: HTTP, LWUITIO, headers

 Description   

I can't find anyway to read the http response headers using LWUITIO, would you please add access to these headers



 Comments   
Comment by vprise [ 03/Apr/11 ]

You are correct, I committed a simple implementation for this just now. Thanks.





[JERSEY-967] Jersey Expires Header not working Created: 08/Feb/12  Updated: 08/Aug/13  Resolved: 16/Feb/12

Status: Resolved
Project: jersey
Component/s: None
Affects Version/s: 1.11
Fix Version/s: 1.17

Type: Bug Priority: Minor
Reporter: francesco23u Assignee: Pavel Bucek
Resolution: Invalid Votes: 0
Labels: None
Remaining Estimate: Not Specified
Time Spent: Not Specified
Original Estimate: Not Specified
Environment:

windows 7; Apache Tomcat 7


Tags: expires, http, jersey

 Description   

Each time I browse a REST resource with Chrome, I notice that there's an HTTP Header Expires set to Thu, 01 Jan 1970 01:00:00 CET.

I tried to edit the Response adding:

return Response.ok( myObject ).expires(new Date(System.currentTimeMillis() + 3000);

Unfortunately, this adds another HTTP Header Expires instead of replacing the old one.



 Comments   
Comment by Martin Matula [ 15/Feb/12 ]

Pavel, please evaluate.

Comment by Pavel Bucek [ 16/Feb/12 ]

Jersey does not return this header by default - looks like this is produced by your container and since its Tomcat, you should check its documentation.

Closing as invalid, feel free to reopen when you can provide more info/proof that issue is in Jersey workspace.





[JAX_WS-966] HTTP redirect of web service Created: 16/Jul/11  Updated: 23/Aug/11

Status: Open
Project: jax-ws
Component/s: wsimport
Affects Version/s: 2.2.6
Fix Version/s: None

Type: Improvement Priority: Major
Reporter: vinhvo Assignee: Unassigned
Resolution: Unresolved Votes: 0
Labels: None
Remaining Estimate: Not Specified
Time Spent: Not Specified
Original Estimate: Not Specified
Environment:

Windows/Linux,Tomcat, JDK 6


Tags: Follow, HTTP, URL, redirect

 Description   

My web service is in tomcat and tomcat is behind a load balancer which redirect the traffic from http to https.

I tried to access the web service behind the balancer but always get an error :

Exception in thread "main" com.sun.xml.internal.ws.client.ClientTransportException: The server sent HTTP status code 301: Moved Permanently
at com.sun.xml.internal.ws.transport.http.client.HttpTransportPipe.checkStatusCode(Unknown Source)
at com.sun.xml.internal.ws.transport.http.client.HttpTransportPipe.process(Unknown Source)
at com.sun.xml.internal.ws.transport.http.client.HttpTransportPipe.processRequest(Unknown Source)
at com.sun.xml.internal.ws.transport.DeferredTransportPipe.processRequest(Unknown Source)
at com.sun.xml.internal.ws.api.pipe.Fiber.__doRun(Unknown Source)
at com.sun.xml.internal.ws.api.pipe.Fiber._doRun(Unknown Source)
at com.sun.xml.internal.ws.api.pipe.Fiber.doRun(Unknown Source)
at com.sun.xml.internal.ws.api.pipe.Fiber.runSync(Unknown Source)
at com.sun.xml.internal.ws.client.Stub.process(Unknown Source)
at com.sun.xml.internal.ws.client.sei.SEIStub.doProcess(Unknown Source)
at com.sun.xml.internal.ws.client.sei.SyncMethodHandler.invoke(Unknown Source)
at com.sun.xml.internal.ws.client.sei.SyncMethodHandler.invoke(Unknown Source)
at com.sun.xml.internal.ws.client.sei.SEIStub.invoke(Unknown Source)
at $Proxy28.getDataForm(Unknown Source)
at com.wapice.netmes.printing.service.impl.PrintingClientServiceImpl.getDataForm(PrintingClientServiceImpl.java:51)
at com.wapice.netmes.printing.main.Main.main(Main.java:96)

I guess the problem is the client does not follow the redirection of the load balancer.



 Comments   
Comment by vinhvo [ 16/Jul/11 ]

On Fri, Jul 15, 2011 at 11:25 PM, Rama Pulavarthi <Rama.Pulavarthi@oracle.com> wrote:
Redirection between HTTP URL and HTTPS URL is not automatically followed as this would be a security issue [1]. As a workaround you can use set the new location as the ENDPOINT_ADDRESS_PROPERTY in the RequestContext,

We have a mechanism to follow it at the tool time. We should allow this at runtime with some user configuration, probably through HttpConfigFeature. Can you please file a bug.

thanks,
Rama Pulavarthi

[1] http://download.oracle.com/javase/6/docs/technotes/guides/deployment/deployment-guide/upgrade-guide/article-17.html

Comment by Martin Grebac [ 23/Aug/11 ]

Changing to improvement.





[GRIZZLY-1666] HTTP request is not fully consumed for persistent connection Created: 19/Mar/14  Updated: 10/Apr/14  Resolved: 24/Mar/14

Status: Resolved
Project: grizzly
Component/s: None
Affects Version/s: None
Fix Version/s: 2.3.12, 3.0

Type: Bug Priority: Major
Reporter: richardwalsh_work Assignee: Unassigned
Resolution: Fixed Votes: 0
Labels: None
Remaining Estimate: Not Specified
Time Spent: Not Specified
Original Estimate: Not Specified

Issue Links:
Related
is related to GRIZZLY-1672 Grizzly stores remainder of malformed... Open
Tags: http

 Description   

GET and DELETE method http requests with a message body are not completely consumed. As a result, the next request that is read on the connection reads the first request's message body as the start line of the new request. The bug is easy to reproduce with a browser REST client plugin - send several DELETE requests with a message body. The first request will respond with a 200, but the second will report a 405.

I tracked down the problem to how the org.glassfish.grizzly.http.HttpServerFilter.prepareRequest() method sets the request's expectedContent boolean property based on the PayloadExpectation associated with the http method. If the request method is associated with PayloadExpectation.NOT_ALLOWED, then downstream processing and request cleanup does not have access to read and consume the content in the message body. The following snippet is in HttpServerFilter.prepareRequest():

final PayloadExpectation payloadExpectation = method.getPayloadExpectation();
if (payloadExpectation != PayloadExpectation.NOT_ALLOWED) {
	request.setExpectContent(
    request.getContentLength() != -1 || request.isChunked());
 } else {
 	request.setExpectContent(method == Method.CONNECT);
}

A simple fix to this problem is to include an additional check for whether the request contentLength is greater than zero:

final PayloadExpectation payloadExpectation = method.getPayloadExpectation();
if (payloadExpectation != PayloadExpectation.NOT_ALLOWED) {
	request.setExpectContent(
	request.getContentLength() != -1 || request.isChunked());
// START NEW CODE
} else if (payloadExpectation == PayloadExpectation.NOT_ALLOWED &&
		request.getContentLength() > 0 ) {
	request.setExpectContent(true);
}
// END NEW CODE
else {
	request.setExpectContent(method == Method.CONNECT);
}

The above change addresses the problem of http methods which the spec does not define whether they can have a request body. However, this lenient approach is probably a bad idea because it allows http methods that are not allowed a request body to optionally have one.

A more robust solution is to adjust the org.glassfish.grizzly.http.Method static constants for the http methods that are undefined to use PayloadExpectation.UNDEFINED. (I saw some previous commits in Method where GET, DELETE, etc statics were in fact set to UNDEFINED). Then adjust the HttpServerFilter.prepareRequest() so the undefined http methods are lenient with respect to having a request body.

final PayloadExpectation payloadExpectation = method.getPayloadExpectation();
if (payloadExpectation != PayloadExpectation.NOT_ALLOWED) {
	request.setExpectContent(
	request.getContentLength() != -1 || request.isChunked());
// START NEW CODE
} else if (payloadExpectation == PayloadExpectation.UNDEFINED &&
		request.getContentLength() > 0 ) {
	request.setExpectContent(true);
}
// END NEW CODE
else {
	request.setExpectContent(method == Method.CONNECT);
}

I do not understand the project's error philosophy, but a more controversial solution would be to use the PayloadExpectation to validate the request semantics and use the Content-Length header to set the request expectedContent. Something like:

boolean hasMessageBody = request.getContentLength() > 0;
final PayloadExpectation payloadExpectation = method.getPayloadExpectation();
if (payloadExpectation == PayloadExpectation.NOT_ALLOWED && hasMessageBody ) {
	// REJECT THE REQUEST (however, that is done)
	throw new SomethingBadHappened();
}

// continue processing the request
request.setExpectContent(hasMessageBody);


 Comments   
Comment by oleksiys [ 21/Mar/14 ]

Hi Richard,

first of all thank you for spending time learning the code and filing this issue!
I've prepare the fix [1], it's now commited both on 2.3.x and master branches.
The changes include:

HttpMethod: GET, HEAD, DELETE methods' expectation was changed back to undefined.

-            new Method("GET", PayloadExpectation.NOT_ALLOWED); // Even though it is UNDEFINED
+            new Method("GET", PayloadExpectation.UNDEFINED);
     public static final Method HEAD =
-            new Method("HEAD", PayloadExpectation.NOT_ALLOWED); // Even though it is UNDEFINED
+            new Method("HEAD", PayloadExpectation.UNDEFINED);
     public static final Method POST
             = new Method("POST", PayloadExpectation.ALLOWED);
     public static final Method PUT
             = new Method("PUT", PayloadExpectation.ALLOWED);
     public static final Method DELETE
-            = new Method("DELETE", PayloadExpectation.NOT_ALLOWED); // Even though it is UNDEFINED
+            = new Method("DELETE", PayloadExpectation.UNDEFINED);

HttpServerFilter:

         final PayloadExpectation payloadExpectation = method.getPayloadExpectation();
         if (payloadExpectation != PayloadExpectation.NOT_ALLOWED) {
-            request.setExpectContent(
-                    request.getContentLength() != -1 || request.isChunked());
+            final boolean hasPayload =
+                    request.getContentLength() > 0 || request.isChunked();
+            
+            if (hasPayload && payloadExpectation == PayloadExpectation.UNDEFINED &&
+                    !allowPayloadForUndefinedHttpMethods) {
+                // if payload is not allowed for the "undefined" methods
+                state.error = true;
+                // Send 400; Bad Request
+                HttpStatus.BAD_REQUEST_400.setValues(response);
+                return;
+            }
+            
+            request.setExpectContent(hasPayload);
         } else {
             request.setExpectContent(method == Method.CONNECT);
         }

Besides that I introduced allowPayloadForUndefinedHttpMethods property, that could be configured either directly on HttpServerFilter or via HttpServer.getConfiguration();

Will appreciate your feedback.

Thank you.

WBR,
Alexey.

[1] https://java.net/projects/grizzly/sources/git/revision/3122babee463ce89cf4251f5efea632aa3ba1ec4

Comment by richardwalsh_work [ 21/Mar/14 ]

Looks great. I like what you did with the allowPayloadForUndefinedHttpMethods property - allows developers to customize how they want to handle it.

Thanks for fixing this!

Rich

Comment by oleksiys [ 24/Mar/14 ]

thank you for your feedback!

fixed.

[2.3.x]
Revision: ff2c0494cb3d167eeb6a467e643235fb54eed707
Date: 2014-03-21 08:11:14 UTC

[master]
Revision: 3122babee463ce89cf4251f5efea632aa3ba1ec4
Date: 2014-03-21 08:11:14 UTC

Log Message:
------------
+ fix issue #1666
https://java.net/jira/browse/GRIZZLY-1666
"HTTP request is not fully consumed for persistent connection"





[GRIZZLY-1607] Buggy parsing of server cookie "expires" in http client - integer overflowing Created: 13/Nov/13  Updated: 15/Nov/13  Resolved: 15/Nov/13

Status: Resolved
Project: grizzly
Component/s: http, http-client
Affects Version/s: 2.3.7
Fix Version/s: None

Type: Bug Priority: Major
Reporter: samally Assignee: Ryan Lubke
Resolution: Fixed Votes: 0
Labels: None
Remaining Estimate: 5 minutes
Time Spent: Not Specified
Original Estimate: 5 minutes

Tags: cookies, http, httpclient

 Description   

Integer overflowing can occure in three places in the org.glassfish.grizzly.http.util.CookieParserUtils class (version 2.3.7) in parseServerCookies methods.

Lines: 1023, 1293, 1544

Original code (division after cast to integer):

cookie.setMaxAge((int) (date.getTime() - System.currentTimeMillis()) / 1000);

Needed code (division before cast to integer):

cookie.setMaxAge((int) ((date.getTime() - System.currentTimeMillis()) / 1000));


 Comments   
Comment by Ryan Lubke [ 15/Nov/13 ]

Changes applied:

2.3.x: d22ef3e777c5d18d412c4cd4833ff46206bb66a0
master: 48d2161bd0d5c98f5bb988d14455acb0d21e2750





[GRIZZLY-1605] Allow to fully disable FileCache (don't add FileCacheFilter to the listener FilterChain) Created: 08/Nov/13  Updated: 15/Nov/13  Resolved: 15/Nov/13

Status: Closed
Project: grizzly
Component/s: http
Affects Version/s: 2.3.7
Fix Version/s: None

Type: Task Priority: Major
Reporter: samally Assignee: Unassigned
Resolution: Works as designed Votes: 0
Labels: None
Remaining Estimate: Not Specified
Time Spent: Not Specified
Original Estimate: Not Specified

Tags: filecache, http

 Description   

I don't use FileCache at all and think that FileCacheFilter is useless for me. But it's called at every request. Please allow to really fully disable FileCache and related stuff.

For example don't initialize FileCache and don't add FileCacheFilter to the listener filter chain if FileCache is disabled before start.

original code
org.glassfish.grizzly.http.server.HttpServer (2.3.7)
method: configureListener
line 677

final FileCache fileCache = listener.getFileCache();
fileCache.initialize(delayedExecutor);
final FileCacheFilter fileCacheFilter = new FileCacheFilter(fileCache);
fileCache.getMonitoringConfig().addProbes(
        serverConfig.getMonitoringConfig().getFileCacheConfig().getProbes());
builder.add(fileCacheFilter);

Change it to this:

final FileCache fileCache = listener.getFileCache();
if (fileCache.isEnabled() {
    fileCache.initialize(delayedExecutor);
    final FileCacheFilter fileCacheFilter = new FileCacheFilter(fileCache);
    fileCache.getMonitoringConfig().addProbes(
        serverConfig.getMonitoringConfig().getFileCacheConfig().getProbes());
    builder.add(fileCacheFilter);
}

Or to this (if initialization is really required)

final FileCache fileCache = listener.getFileCache();
fileCache.initialize(delayedExecutor);
if (fileCache.isEnabled() {
    final FileCacheFilter fileCacheFilter = new FileCacheFilter(fileCache);
    fileCache.getMonitoringConfig().addProbes(
        serverConfig.getMonitoringConfig().getFileCacheConfig().getProbes());
    builder.add(fileCacheFilter);
}

Currently I can remove FileCacheFilter myself after server start via (kotlin code):

if (disableGrizzlyFileCache) {
    val chain = listener.getFilterChain().iterator()
    for (filter in chain) {
        if (filter is FileCacheFilter) {
            chain.remove()
            break
        }
    }
}

But it looks like dirty hack.



 Comments   
Comment by oleksiys [ 12/Nov/13 ]

Hi,

the intention here was to make possible to enable/disable the FileCache at runtime.
The penalty for keeping FileCacheFilter in the FilterChain has to be minimal.

I can suggest you a better hack

listener.registerAddOn(new AddOn() {

     @Override
     public void setup(NetworkListener networkListener, FilterChainBuilder builder) {
         final int idx = builder.indexOfType(FileCacheFilter.class);
         if (idx != -1) {
            builder.remove(idx);
         }
     }
});




[GRIZZLY-1604] notifyTransferEncodingParse is called instead of notifyTransferEncodingSerialize in HttpCodecFilter.serializeWithTransferEncoding Created: 07/Nov/13  Updated: 07/Nov/13  Resolved: 07/Nov/13

Status: Resolved
Project: grizzly
Component/s: http
Affects Version/s: 2.3.7
Fix Version/s: 2.3.8, 3.0

Type: Bug Priority: Minor
Reporter: samally Assignee: Ryan Lubke
Resolution: Fixed Votes: 0
Labels: None
Remaining Estimate: Not Specified
Time Spent: Not Specified
Original Estimate: Not Specified

Tags: http, monitoring

 Description   

notifyTransferEncodingParse is called instead of notifyTransferEncodingSerialize in HttpCodecFilter.serializeWithTransferEncoding method.



 Comments   
Comment by Ryan Lubke [ 07/Nov/13 ]

Changes applied:

2.3.x: b1ce31ae571955a8a77ce4f0ba00480e4095cab5
master: a8a758eb8e5f305e661da44605d4397a6589a59d





[GLASSFISH-21059] Http Compression when use websocket Created: 02/May/14  Updated: 04/Jun/14

Status: Open
Project: glassfish
Component/s: web_socket
Affects Version/s: 4.0
Fix Version/s: None

Type: Improvement Priority: Major
Reporter: dungld Assignee: Pavel Bucek
Resolution: Unresolved Votes: 0
Labels: None
Remaining Estimate: Not Specified
Time Spent: Not Specified
Original Estimate: Not Specified
Environment:

Ubuntu Linux Server 64 bit


Tags: 4_0_1-approved, http, websocket

 Description   

When I use Glassfish 4.0 with Tyrus 1.0, I can enable http compression feature on Glassfish.

But when I use Glassfish 4.0.1 b3 with Tyrus 1.5, I can not enable http compression feature because when I tick compression checkbox, my webpage cannot display (included javascript, css...)

I think compression feature is very important when loading page initial. I hope Glassfish team improve it for next release.

Thank you.






[GLASSFISH-19793] GlassFish 3.1.2.2-x does not follow Servlet spec 3.0 web.xml cookie-config specs. Created: 08/Mar/13  Updated: 29/Mar/13  Resolved: 29/Mar/13

Status: Closed
Project: glassfish
Component/s: web_container
Affects Version/s: 3.1.2.2
Fix Version/s: 4.0

Type: Bug Priority: Major
Reporter: gfuser9999 Assignee: Shing Wai Chan
Resolution: Invalid Votes: 0
Labels: None
Remaining Estimate: Not Specified
Time Spent: Not Specified
Original Estimate: Not Specified
Environment:

GlassFish 3.1.2.2 and whatever latest
Servlet spec 3.0 compliance code for Cookie secure disabling.


Tags: HTTP, cookieSecure, httpOnly, secure, servlet, specs, web

 Description   

Problem
=======
For a standand Web 3.0 web using Servlet spec 3.0 web.xml to define the cookie-config to disable the HTTP secure cookie to false, does not work.

Eg:
1. WEB-INF/web.xml

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://java.sun.com/xml/ns/javaee"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
  version="3.0">

    <display-name>web</display-name>
    <distributable/>
    <session-config>
        <cookie-config>
           <http-only>false</http-only>
           <secure>false</secure>
        </cookie-config>
    </session-config>
    <welcome-file-list>
        <welcome-file>index.jsp</welcome-file>
    </welcome-file-list>
</web-app>

2. Deploy WAR with this WEB-INF/web.xml and an empty index.jsp.

3. Connect to https://localhost:8443/test/index.jsp. (Use HTTPS)
You see the following response:

HTTP/1.1 200 OK
X-Powered-By: JSP/2.2
Server: Oracle GlassFish Server 3.1.2.4
Set-Cookie: JSESSIONID=85801ba565e620b5994dc80da18f; Path=/test; Secure
Content-Type: text/html;charset=ISO-8859-1
Content-Length: 2
Date: Fri, 08 Mar 2013 04:52:39 GMT

Notice that we managed to get the HttpOnly disable but the Secure is there

Root cause.

GlassFish 3.x code does not take into the consideration of the <secure>
web.xml tag. Instead it seems that it uses the dynamic property
of the request CookieSecureType.DYNAMIC even though there is no
custom glassfish-web.xml set. The code should be better in
setting CookieSecureType to FALSE IF one EXPLICITLY do set
the web.xml <secure> setting and not use GlassFish behaviour
override the standard web.xml.

Issue: Servlet Compliance behaviour deviation.



 Comments   
Comment by Shing Wai Chan [ 26/Mar/13 ]

The following comment is from schema file.

      <xsd:element name="secure"
                   type="javaee:true-falseType"
                   minOccurs="0">
        <xsd:annotation>
          <xsd:documentation>

            Specifies whether any session tracking cookies created
            by this web application will be marked as secure
            even if the request that initiated the corresponding session
            is using plain HTTP instead of HTTPS

          </xsd:documentation>
        </xsd:annotation>
      </xsd:element>

It states explicitly about the behavior of http.

What is the use case of having https with insecure cookies? In that case, the session can be hijacked.

Comment by Shing Wai Chan [ 29/Mar/13 ]

We have discussed this in Servlet 3.1 expert group. The behavior in GlassFish is correct. More description is added in Servlet 3.1 schema.





[GLASSFISH-19354] HTTP Double Gzip Compression Created: 17/Nov/12  Updated: 12/Mar/13  Resolved: 12/Mar/13

Status: Resolved
Project: glassfish
Component/s: grizzly-kernel
Affects Version/s: 3.1.2, 3.1.2.2
Fix Version/s: 4.0

Type: Bug Priority: Major
Reporter: arosso Assignee: oleksiys
Resolution: Fixed Votes: 0
Labels: None
Remaining Estimate: Not Specified
Time Spent: Not Specified
Original Estimate: Not Specified
Environment:

Amazon Linux 2012 09


Attachments: Zip Archive doublecompression-test.zip    
Tags: grizzly, gzip, http

 Description   

See: http://www.java.net/forum/topic/glassfish/glassfish/glassfish-double-compression for discussion.

The Grizzly http listener does not detect that a response is already Gzipped and gzips it again causing the output to be garbled. This did not use to happen in Glassfish 2.1.x but seems to happen in 3.1.x.

To reproduce deploy the attached web app directory into Glassfish 3.1.2.2 and access index.html page. Now switch on compression and the output will be garbled.

domain.xml compression settings are:

<http ... compression="on" compressable-mime-type="text/html,text/xml,text/javascript,text/css">



 Comments   
Comment by oleksiys [ 19/Nov/12 ]

Related to Grizzly issue
http://java.net/jira/browse/GRIZZLY-1367

Comment by oleksiys [ 12/Mar/13 ]

fixed in GF 4





[GLASSFISH-19070] Glassfish creates more than one http session in realm authentication Created: 11/Sep/12  Updated: 10/Oct/12  Resolved: 10/Oct/12

Status: Resolved
Project: glassfish
Component/s: web_container
Affects Version/s: 3.1.2
Fix Version/s: 4.0_b54

Type: Bug Priority: Critical
Reporter: lenz11 Assignee: Shing Wai Chan
Resolution: Fixed Votes: 1
Labels: None
Remaining Estimate: Not Specified
Time Spent: Not Specified
Original Estimate: Not Specified

Tags: authentication, double, http, realm, sessions

 Description   

When changeSessionIdOnAuthentication==true (default) and user authenticates with Realm - Glassfish calls sessions.setId(with_new_generated_id) which executes (through tellNew()): fireSessionEvent(Session.SESSION_CREATED_EVENT, null)
It is still the same session, but with new Id (no SESSION_DESTROYED_EVENT is called). This gives as a problem similar to:
http://stackoverflow.com/questions/11842343/glassfish-create-more-than-one-http-session-in-realm-authentication - and only half of sessions are being destroyed (see counter in administration panel: application monitoring/activeSessions).

This is because StandardSession.setId() calls method tellNew() even, if it is still the same session (but with new generated Id).

Now setId() method in web-core/src/main/java/org/apache/catalina/session/StandardSession.java looks like:

public void setId(String id)

{ if ((this.id != null) && (manager != null)) manager.remove(this); this.id = id; if (manager != null) manager.add(this); tellNew(); // this ALWAYS calls event: Session.SESSION_CREATED_EVENT }

but I think it should be something like this:

public void setId(String id)

{ if ((this.id != null) && (manager != null)) manager.remove(this); String old_id = this.id; this.id = id; if (manager != null) manager.add(this); if (old_id == null) tellNew(); // only call Session.SESSION_CREATED_EVENT if it is a new Session }

so the new session will be created only when old session Id is null.



 Comments   
Comment by Shing Wai Chan [ 10/Oct/12 ]

The fix has been checkin to GlassFish 4.0 b54 as follows:
------------------------------------------------------------------------
r55887 | swchan2 | 2012-09-10 12:57:46 -0700 (Mon, 10 Sep 2012) | 2 lines

integrate javax.servlet-api 3.1-b02, implement changeSessionId

------------------------------------------------------------------------





[GLASSFISH-19035] [Perf] Performance degradation when using dynamic http thread pool Created: 23/Aug/12  Updated: 16/Feb/13  Resolved: 16/Feb/13

Status: Resolved
Project: glassfish
Component/s: grizzly-kernel
Affects Version/s: 4.0_b40
Fix Version/s: 4.0_b60

Type: Bug Priority: Major
Reporter: deep_singh Assignee: oleksiys
Resolution: Fixed Votes: 0
Labels: None
Remaining Estimate: Not Specified
Time Spent: Not Specified
Original Estimate: Not Specified
Environment:

Linux 2.2.16 OEL x64


Tags: HTTP, JSP, PSRBUG, ThreadPool, glassfish

 Description   

Seeing significant performance degradation when using dynamic http thread pool when running a JSP HTTP micro benchmark. The degradation has been traced to a hot ReentrantLock in SyncThreadPool implementation of thread pool. When FixedThreadPool is used, there is significant improvement in performance results compared to dynamic thread pool.

Have tried a patch from Alexey replacing ReentrantLock with a Synchronized block, but that is not yielding much improvement.

The benchmark is a simple war file with 3 JSPs doing HelloWorld, showing current date and maintaining a simple user session with hit count.



 Comments   
Comment by deep_singh [ 16/Nov/12 ]

Re-tried the Synchronized block change in dynamic thread pool on b62 with patch built with latest Grizzly 2.3-beta8 binaries. Found 17% improvement when compared to Reentrant lock and 7% improvement when compared to Glassfish 3.1.2 . This test was done with thread pool size min=1 max=8 on a 4 CPU machine and used JSP POST Reader test with 50 concurrent users.

Comment by oleksiys [ 16/Feb/13 ]

fixed





[GLASSFISH-18803] no response for a chunked package Created: 13/Jun/12  Updated: 14/Dec/12

Status: Open
Project: glassfish
Component/s: grizzly-kernel
Affects Version/s: 3.1.2_b23
Fix Version/s: None

Type: Bug Priority: Critical
Reporter: yavuzs Assignee: oleksiys
Resolution: Unresolved Votes: 0
Labels: None
Remaining Estimate: 1 day
Time Spent: Not Specified
Original Estimate: 1 day
Environment:

SunOs, x86, 64bit


Attachments: File seac808012.cap    
Tags: http, http-listener

 Description   

there is a server that sends us chunked requests (by POST), our application on glassfish takes these packages and process them. but somehow, some of the packages are not processed by the application, also there is no log activity about these packages. but when we capture the network activity we can see that the request has come to the server.
we tried "-Dcom.sun.enterprise.web.connector.grizzly.enableSnoop=true" parameter. with this parameter, for the lost request there is no log.
here is a lost request:
Host: 192.168.100.10:49205
Transfer-Encoding: chunked

185
<?xml version='1.0' encoding='UTF-8'?>
<env:Envelope xmlns:env='http://www.w3.org/2003/05/soap-envelope' xmlns:seadac='http://www.schange.com/2004/SeaDAC/triggers'>
<env:Header><seadac:transaction transaction-id='

{20321632-B758-442a-ADFE-6E4607343AE3}

' origination-time='2012-06-12T08:29:04Z' env:role='http://www.w3.org/2003/05/soap-envelope/ultimateReceiver'/></env:Header>
<env:Body>
80
<seadac:subscription-notification subscription-id='

{1942B6B8-158F-4279-B9E9-0429671BEC67}

' current-request='3' next-request='4'>
c7
<seadac:hierarchy-changed hierarchy-uid='539401'><seadac:node-added hierarchy-uid='539710' asset-uid='528673'/></seadac:hierarchy-changed></seadac:subscription-notification></env:Body></env:Envelope>
0

you can find the capture attached.
frame 7824 and 7825 are the same request that the server sends to all subscribed clients. for this example there are two client subscribed. the gf application and the tomcat application. as you see, at the frame 7824 tomcat responded the request but at the frame 7825 fg did not respond the request.
regards,



 Comments   
Comment by yavuzs [ 19/Jun/12 ]

any response?

Comment by oleksiys [ 14/Dec/12 ]

sorry for the late response.
is it still the case w/ Glassfish 3.1.2.2?

thanks.

Comment by yavuzs [ 14/Dec/12 ]

the version is : GlassFish Server Open Source Edition 3.1.2 (build 23)

Comment by oleksiys [ 14/Dec/12 ]

yes, I understand, but there is a newer version (patch release) where this issue might have been fixed.
are you able to reproduce the issue consistently, or it happens sporadically?

Comment by yavuzs [ 14/Dec/12 ]

it happens sporadically. we didn't try new patch yet.





Generated at Sun Aug 02 04:53:21 UTC 2015 using JIRA 6.2.3#6260-sha1:63ef1d6dac3f4f4d7db4c1effd405ba38ccdc558.