Giải thích lỗi error 500 java.io.ioexception stream closed năm 2024

The session timeout may have been the issue and we are looking into using the guidelines to setup loginRequiredMarkers. However, we don't believe this issue is related to markers. It appears that the client side is prematurely closing the socket connection.

1. SmartClient Version: v10.0p_2015-02-25/PowerEdition Deployment (built 2015-02-25)

2. Chrome Version 40.0.2214.115 m

3. === 2015-03-12 15:35:24,210 [sor2] INFO RequestContext - URL: '/<removed>/<removed>/<removed>', User-Agent: 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/40.0.2214.115 Safari/537.36': Safari with Accept-Encoding header Mar 12, 2015 3:35:24 PM org.apache.catalina.core.ApplicationContext log SEVERE: Exception while dispatching incoming RPC call java.io.IOException: Stream closed at org.apache.catalina.connector.InputBuffer.read(InputBuffer.java:325) at org.apache.catalina.connector.CoyoteInputStream.read(CoyoteInputStream.java:162) at com.google.gwt.user.server.rpc.RPCServletUtils.readContent(RPCServletUtils.java:224) at com.google.gwt.user.server.rpc.RPCServletUtils.readContentAsGwtRpc(RPCServletUtils.java:252) at com.google.gwt.user.server.rpc.AbstractRemoteServiceServlet.readContent(AbstractRemoteServiceServlet.java:182) at com.google.gwt.user.server.rpc.RemoteServiceServlet.processPost(RemoteServiceServlet.java:364) at com.google.gwt.user.server.rpc.AbstractRemoteServiceServlet.doPost(AbstractRemoteServiceServlet.java:62) at javax.servlet.http.HttpServlet.service(HttpServlet.java:637) at javax.servlet.http.HttpServlet.service(HttpServlet.java:717) at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:290) at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206) at com.alcatel_lucent.aware.web.wnganalytic.server.SecurityFilter.doFilter(SecurityFilter.java:79) at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:235) at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206) at com.isomorphic.servlet.CompressionFilter._doFilter(CompressionFilter.java:260) at com.isomorphic.servlet.BaseFilter.doFilter(BaseFilter.java:83) at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:235) at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206) at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:233) at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:191) at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:127) at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:102) at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:109) at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:298) at org.apache.jk.server.JkCoyoteHandler.invoke(JkCoyoteHandler.java:190) at org.apache.jk.common.HandlerRequest.invoke(HandlerRequest.java:291) at org.apache.jk.common.ChannelSocket.invoke(ChannelSocket.java:769)) at org.apache.jk.common.ChannelSocket.processConnection(ChannelSocket.java:698) at org.apache.jk.common.ChannelSocket$SocketConnection.runIt(ChannelSocket.java:891) at org.apache.tomcat.util.threads.ThreadPool$ControlRunnable.run(ThreadPool.java:690) at java.lang.Thread.run(Thread.java:745)

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Comments

Environment Details

  • GlassFish Version (and build number): 4.1
  • JDK version: 1.7
  • OS: win 7
  • Database: none

Problem Description

JSP compiling process is done at the first access. at this time, I debug following the operating steps, IOException ("Stream closed") has occurred. it occur in the debug, but I think it will occur in high concurrent accessing apps. Is it a bug of Glassfish, since two threads get the same jarFile.

Steps to reproduce

1.Deploy test app1 and app2 and start cluster. 2.Set breakpoints

org.apache.jasper.runtime.TldScanner.scanJar(TldScanner.java:447)  Set a breakpoint here
   private void scanJar(JarURLConnection conn, List<String> tldNames,boolean isLocal) throws JasperException {
  ...                        
  try {
    jarFile = conn.getJarFile();
    if (tldNames != null) {
      for (String tldName : tldNames) {
        JarEntry entry = jarFile.getJarEntry(tldName);
        InputStream stream = jarFile.getInputStream(entry);
        tldInfoA.add(scanTld(resourcePath, tldName, stream)); ★

3.access app1 and app2. 4.At this time, two threads stop at the breakpoint. 5.First, resume the thread of app1. Leave the thread of app 2 stopped at the breakpoint. 6.When executing the thread of app 2, IOException ("Stream closed") is output because ★closed value is set to true.

Impact of Issue

The following log is reported and the second app return '500'

[#|2018-07-12T02:56:08.230-0700|WARNING|||_ThreadID=67;_ThreadName=http-thread-pool-28292(2);|ApplicationDispatcher[/Demo2] PWC1231: Servlet.service() for servlet jsp threw exception java.io.IOException: Stream closed at java.util.zip.InflaterInputStream.ensureOpen(InflaterInputStream.java:67) at java.util.zip.InflaterInputStream.read(InflaterInputStream.java:121) at com.sun.org.apache.xerces.internal.impl.XMLEntityManager$RewindableInputStream.read(XMLEntityManager.java:2873) at com.sun.org.apache.xerces.internal.impl.XMLEntityManager.setupCurrentEntity(XMLEntityManager.java:664) at com.sun.org.apache.xerces.internal.impl.XMLVersionDetector.determineDocVersion(XMLVersionDetector.java:189) at com.sun.org.apache.xerces.internal.parsers.XML11Configuration.parse(XML11Configuration.java:812) at com.sun.org.apache.xerces.internal.parsers.XML11Configuration.parse(XML11Configuration.java:777) at com.sun.org.apache.xerces.internal.parsers.XMLParser.parse(XMLParser.java:141) at com.sun.org.apache.xerces.internal.parsers.DOMParser.parse(DOMParser.java:243) at com.sun.org.apache.xerces.internal.jaxp.DocumentBuilderImpl.parse(DocumentBuilderImpl.java:347) at org.apache.jasper.xmlparser.ParserUtils.parseXMLDocument(ParserUtils.java:298) at org.apache.jasper.xmlparser.ParserUtils.parseXMLDocument(ParserUtils.java:368) at org.apache.jasper.runtime.TldScanner.scanTld(TldScanner.java:600) at org.apache.jasper.runtime.TldScanner.scanJar(TldScanner.java:447) at org.apache.jasper.runtime.TldScanner.scanJars(TldScanner.java:737) at org.apache.jasper.runtime.TldScanner.scanTlds(TldScanner.java:350) at org.apache.jasper.runtime.TldScanner.getLocation(TldScanner.java:283) at org.apache.jasper.JspCompilationContext.getTldLocation(JspCompilationContext.java:589) at org.apache.jasper.compiler.Parser.parseTaglibDirective(Parser.java:500) at org.apache.jasper.compiler.Parser.parseDirective(Parser.java:582) at org.apache.jasper.compiler.Parser.parseElements(Parser.java:1652) at org.apache.jasper.compiler.Parser.parse(Parser.java:185) at org.apache.jasper.compiler.ParserController.doParse(ParserController.java:244) at org.apache.jasper.compiler.ParserController.parse(ParserController.java:145) at org.apache.jasper.compiler.Compiler.generateJava(Compiler.java:212) at org.apache.jasper.compiler.Compiler.compile(Compiler.java:451) at org.apache.jasper.JspCompilationContext.compile(JspCompilationContext.java:627) at org.apache.jasper.servlet.JspServletWrapper.service(JspServletWrapper.java:375) at org.apache.jasper.servlet.JspServlet.serviceJspFile(JspServlet.java:473) at org.apache.jasper.servlet.JspServlet.service(JspServlet.java:377) at javax.servlet.http.HttpServlet.service(HttpServlet.java:770) at org.apache.catalina.core.StandardWrapper.service(StandardWrapper.java:1550) at org.apache.catalina.core.ApplicationDispatcher.doInvoke(ApplicationDispatcher.java:809) at org.apache.catalina.core.ApplicationDispatcher.invoke(ApplicationDispatcher.java:671) at org.apache.catalina.core.ApplicationDispatcher.processRequest(ApplicationDispatcher.java:505) at org.apache.catalina.core.ApplicationDispatcher.doDispatch(ApplicationDispatcher.java:476) at org.apache.catalina.core.ApplicationDispatcher.dispatch(ApplicationDispatcher.java:355) at org.apache.catalina.core.ApplicationDispatcher.forward(ApplicationDispatcher.java:305) ... at java.lang.Thread.run(Thread.java:745)

Occurrence condition:

1.At the same time when accessing app 1 and app 2 (JSP compiling process is done at first access), two processing threads (thread 1, 2) are activated, and these two threads get the same jarFile ★ 1. 2.At the end of the scanJar () method of app 1 (thread 1), jarFile is closed. ★ 3. 3.Since jarFile is closed, the closed state of stream★2 of app 2 (thread 2) is true. 4.When app2 (thread 2) executes scanTld (), an IOException ("Stream closed") occurs because the closed state of stream has become true.

org.apache.jasper.runtime.TldScanner.scanJar(TldScanner.java:447)
    private void scanJar(JarURLConnection conn, List<String> tldNames,boolean isLocal) throws JasperException {
  ...                        
  try {
    jarFile = conn.getJarFile(); ★1
    if (tldNames != null) {
       for (String tldName : tldNames) {
        JarEntry entry = jarFile.getJarEntry(tldName);
        InputStream stream = jarFile.getInputStream(entry);
        tldInfoA.add(scanTld(resourcePath, tldName, stream)); ★2
       ...               
  finally {
              if (jarFile != null) {
      try {
        jarFile.close(); ★3
      } catch (Throwable t) {
        // ignore
      }
    }

The text was updated successfully, but these errors were encountered:

  • Issue Imported From: https://github.com/javaee/glassfish/issues/22552
  • Original Issue Raised By:@micRo-wlY
  • Original Issue Assigned To: Unassigned

Thoughts: When multiple threads read and close a jar file at the same time, exclusive control is performed.

Verification result: Avoidable

amendment:

org.apache.jasper.runtime.TldScanner private void scanJar (JarURLConnection conn, List tldNames, boolean isLocal) throws JasperException {

String resourcePath = conn.getJarFileURL (). ToString (); TldInfo [] tldInfos = jarTldCacheLocal.get (resourcePath);

// Optimize for most common cases: jars known to NOT have tlds if (tldInfos! = null && tldInfos.length == 0) { try { conn.getJarFile (). close (); } catch (IOException ex) { // ignored } return; }

// scan the tld if the jar has not been cached. + synchronized (TldScanner.class) { if (tldInfos == null) { JarFile jarFile = null; ArrayList tldInfoA = new ArrayList (); try { jarFile = conn.getJarFile (); if (tldNames! = null) { for (String tldName: tldNames) { JarEntry entry = jarFile.getJarEntry (tldName); InputStream stream = jarFile.getInputStream (entry); tldInfoA.add (scanTld (resourcePath, tldName, stream)); } } else { Enumeration entries = jarFile.entries (); while (entries.hasMoreElements ()) { JarEntry entry = entries.nextElement (); String name = entry.getName (); if (! name.startsWith ("META-INF /")) continue; if (! name.endsWith (". tld")) continue; InputStream stream = jarFile.getInputStream (entry); tldInfoA.add (scanTld (resourcePath, name, stream)); } } } catch (IOException ex) { if (resourcePath.startsWith (FILE_PROTOCOL) && ! ((new File (resourcePath)). exists ())) { if (log.isLoggable (Level.WARNING)) { log.log (Level.WARNING, Localizer.getMessage ("jsp.warn.nojar", resourcePath), ex); } } else { throw new JasperException ( Localizer.getMessage ("jsp.error.jar.io", resourcePath), ex); } } finally {

if (jarFile! = null) { try { jarFile.close (); } catch (Throwable t) { // ignore } } } // Update the jar TLD cache tldInfos = tldInfoA.toArray (new TldInfo [tldInfoA.size ()]); jarTldCacheLocal.put (resourcePath, tldInfos); if (! isLocal) { // Also update the global cache; jarTldCache.put (resourcePath, tldInfos); } } +}

// Iterate over tldinfos to add listeners or to tldlocations for (TldInfo tldInfo: tldInfos) { if (scanListeners) { addListener (tldInfo, isLocal); } mapTldLocation (resourcePath, tldInfo, isLocal); }

}

There are some conditions to correct

The occurrence conditions can be divided into the case of using jstl and not using jstl, specifically refer to the following:

Not using jstl: case1 ①The following definitions in JSP <@taglib uri="demo-taglib" prefix="demo" %> And, ②the following taglib defined in the web.xml

<jsp-config>
    <taglib>
      <taglib-uri>demo-taglib</taglib-uri>
      <taglib-location>/WEB-INF/demo.tld</taglib-location>
    </taglib>
  </jsp-config>

case2 The following definitions in JSP <@taglib uri="WEB-INF/demo.tld" prefix="demo" %>

Using jstl: When the JSP contains jstl related tags (eg <c:>)

Is there anyone who can respond as quickly as possible, thanks very much. :)

Is there anyone who can respond as quickly as possible, thanks very much. :)

Why don't you make a PR and test if you know the fix?

Why don't you make a PR and test if you know the fix? I fixed it with the amendment I commented and it worked well. But my amendment is not authoritative, is there a community guy to confirm it?

It is easier for people to discuss a PR than look for embedded code in a comment as the PR will highlight diffs etc. and people can comment on individual lines of code. A PR can also be run through Jenkins tests to see if it compiles and passes all tests.

I have two questions I would like to ask:

  1. What is PR, can you explain it briefly, or give a reference link?
  2. As the GF side, how do you think about this issue, and are you going to make corrections?

After we corrected it according to our amendment, we reproduced it according to the reproduction step, and found that we could avoid the problem. I hope that you can help us confirm whether there is a problem with this correction.

Sorry this is late, we've been behind on updating the GlassFish web site. In the mean time, you can find out more about Pull Requests here.

I'm not at all familiar with the code you're looking at, so I have some questions...

For this problem to occur, it seems like the same JarURLConnection object would need to be used in the call to TldScanner.scanJar for both applications. Where is the JarURLConnection object coming from? Why is it the same for both applications? Is the scanning being done for some shared tag library? Is something caching the JarURLConnection object, causing it to be shared across applications?

Maybe the right fix is to ensure there's a separate JarURLConnection object for each application?

The reproduction is performed in accordance with the reproduction handwriting provided by itself, and the conn object is viewed during the reproduction. Conn when accessing app1: conn JarURLConnection (id=6231)

Conn when accessing app2: conn JarURLConnection (id=6271)

According to the results, they are not the same object.

But the jarFile taken from conn is the same object. jarFile when accessing app1: jarFile URLJarFile (id=6229)

jarFile when accessing app2: jarFile URLJarFile (id=6229)

According to your correction suggestion, make sure that the two apps have two different JarURLConnections. But from the current survey, they are indeed different JarURLConnection, the same jarFile is obtained. Therefore, is it still according to my correction method, or there are still other corrections. Please point the specific correction direction.

I see the JarURLConnection is using a cache that shares the cached JarFile between all JarURLConnection objects with the same URL. That's what's preventing each app from getting its own copy. The right fix might be to call jarURLConnection.setUseCaches(false) immediately after creating the object.

I'm only worried about what impact that would have on performance or memory use. Your alternative of single-threading the TLD scanner might turn out to be better, but it has a potential performance cost as well. Since the problem is that multiple threads are operating on the same JarFile object, why not just synchronize on the JarFile object itself? Since both threads are racing to process the JarFile and add the TLD entries to the cache, there's no point in both of them doing that. One of them might as well update the cache while the other waits and checks the cache again.

It's surprising that no other use of JarURLConnection in GlassFish runs into this issue. Do other uses do something to ensure that two threads aren't operating on the same JarFile object?

  1. Call` jarURLConnection.setUseCaches(false)` immediately after creating the object.

In the original code, this setting has been made, but the settings have not taken effect.

    private void scanJars() throws Exception {
      ...
            if (jconn != null) {
                jconn.setUseCaches(false);

When this method is executed, useCaches is not set to false.

Thread [main] (Suspended)  
  ...
  FileURLConnection(URLConnection).setUseCaches(boolean)
  JarURLConnection.setUseCaches(boolean)
  TldScanner.scanJars()

The useCaches in FileURLConnection.setUseCaches are successfully set to false. But when returned, useCaches becomes true again. I can't understand this point. Do you have any good ideas?

  1. Just synchronize on the JarFile object itself. I made the following corrections and verified the results so that the fix can also circumvent the problem, and because the lock object is just a JarFile, the scope of influence is smaller.

    private void scanJar() throws Exception {
    try {
            jarFile = conn.getJarFile();
            +synchronized (jarFile) {
            if (tldNames != null) {
                for (String tldName : tldNames) {
                    JarEntry entry = jarFile.getJarEntry(tldName);
                    InputStream stream = jarFile.getInputStream(entry);
                    tldInfoA.add(scanTld(resourcePath, tldName, stream));
                }
            } else {
                ...
                }
            }
            +}

  1. Make sure that two threads don't call the same JarFile object. I searched the code and found a similar operation in the methods of the following classes.

org.apache.jasper.runtime.TldScanner.scanJar(TldScanner.java:447)
    private void scanJar(JarURLConnection conn, List<String> tldNames,boolean isLocal) throws JasperException {
  ...                        
  try {
    jarFile = conn.getJarFile(); ★1
    if (tldNames != null) {
       for (String tldName : tldNames) {
        JarEntry entry = jarFile.getJarEntry(tldName);
        InputStream stream = jarFile.getInputStream(entry);
        tldInfoA.add(scanTld(resourcePath, tldName, stream)); ★2
       ...               
  finally {
              if (jarFile != null) {
      try {
        jarFile.close(); ★3
      } catch (Throwable t) {
        // ignore
      }
    }

0

I'm not sure when this method will be called. I did some instruction execution, but didn't call this method. About this method, do you know when it is called?

I don't know why

1 isn't working, but it's probably not the best solution so let's abandon that.

For

2, the goal should be that if two threads are both calling scanJar at the "same time",

one of them gets the synchronization lock and does all the work, while the other one waits for the synchronization lock and then discovers that all the work has been done and so does nothing. The right way to do this is to move the check of "has this jar file already been scanned" to inside the

org.apache.jasper.runtime.TldScanner.scanJar(TldScanner.java:447)
    private void scanJar(JarURLConnection conn, List<String> tldNames,boolean isLocal) throws JasperException {
  ...                        
  try {
    jarFile = conn.getJarFile(); ★1
    if (tldNames != null) {
       for (String tldName : tldNames) {
        JarEntry entry = jarFile.getJarEntry(tldName);
        InputStream stream = jarFile.getInputStream(entry);
        tldInfoA.add(scanTld(resourcePath, tldName, stream)); ★2
       ...               
  finally {
              if (jarFile != null) {
      try {
        jarFile.close(); ★3
      } catch (Throwable t) {
        // ignore
      }
    }

1 block. That would require some rearranging of the code.

Note that I'm not really familiar with this code or what it's trying to accomplish. There's a whole bunch of work that's done if

org.apache.jasper.runtime.TldScanner.scanJar(TldScanner.java:447)
    private void scanJar(JarURLConnection conn, List<String> tldNames,boolean isLocal) throws JasperException {
  ...                        
  try {
    jarFile = conn.getJarFile(); ★1
    if (tldNames != null) {
       for (String tldName : tldNames) {
        JarEntry entry = jarFile.getJarEntry(tldName);
        InputStream stream = jarFile.getInputStream(entry);
        tldInfoA.add(scanTld(resourcePath, tldName, stream)); ★2
       ...               
  finally {
              if (jarFile != null) {
      try {
        jarFile.close(); ★3
      } catch (Throwable t) {
        // ignore
      }
    }

2, and then some work after that that's done whether it's null or not. I believe this latter work is application-specific and so should be outside the synchronized block, but let me know if that sounds wrong.

If you can change the code in this way and test it, and submit a Pull Request, I'll review and approve it.

I don't know about

3; that looks like a problem for another day! :-)

Thanks.

I am very sorry to have responded for so long. I have fixed and tested it according to your prompts, and I have summitted a pull request. In addition, TldScanner belongs to eclipse-ee4j/jsp-api instead of eclipse-ee4j/glassfish. Can you help to deal about it?Thanks!

jsp-api is a different project with potentially different team members.

This issue has been marked as inactive and old and will be closed in 7 days if there is no further activity. If you want the issue to remain open please add a comment