View Javadoc
1   /*
2    * Copyright (c) 2005, 2008, Oracle and/or its affiliates. All rights reserved.
3    * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4    *
5    * This code is free software; you can redistribute it and/or modify it
6    * under the terms of the GNU General Public License version 2 only, as
7    * published by the Free Software Foundation.  Oracle designates this
8    * particular file as subject to the "Classpath" exception as provided
9    * by Oracle in the LICENSE file that accompanied this code.
10   *
11   * This code is distributed in the hope that it will be useful, but WITHOUT
12   * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13   * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14   * version 2 for more details (a copy is included in the LICENSE file that
15   * accompanied this code).
16   *
17   * You should have received a copy of the GNU General Public License version
18   * 2 along with this work; if not, write to the Free Software Foundation,
19   * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20   *
21   * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22   * or visit www.oracle.com if you need additional information or have any
23   * questions.
24   */
25  
26  package sun.net.www.http;
27  
28  import java.io.IOException;
29  import java.util.LinkedList;
30  import sun.net.NetProperties;
31  import java.security.AccessController;
32  import java.security.PrivilegedAction;
33  
34  /**
35   * This class is used to cleanup any remaining data that may be on a KeepAliveStream
36   * so that the connection can be cached in the KeepAliveCache.
37   * Instances of this class can be used as a FIFO queue for KeepAliveCleanerEntry objects.
38   * Executing this Runnable removes each KeepAliveCleanerEntry from the Queue, reads
39   * the reamining bytes on its KeepAliveStream, and if successful puts the connection in
40   * the KeepAliveCache.
41   *
42   * @author Chris Hegarty
43   */
44  
45  @SuppressWarnings("serial")  // never serialized
46  class KeepAliveStreamCleaner
47      extends LinkedList<KeepAliveCleanerEntry>
48      implements Runnable
49  {
50      // maximum amount of remaining data that we will try to cleanup
51      protected static int MAX_DATA_REMAINING = 512;
52  
53      // maximum amount of KeepAliveStreams to be queued
54      protected static int MAX_CAPACITY = 10;
55  
56      // timeout for both socket and poll on the queue
57      protected static final int TIMEOUT = 5000;
58  
59      // max retries for skipping data
60      private static final int MAX_RETRIES = 5;
61  
62      static {
63          final String maxDataKey = "http.KeepAlive.remainingData";
64          int maxData = AccessController.doPrivileged(
65              new PrivilegedAction<Integer>() {
66                  public Integer run() {
67                      return NetProperties.getInteger(maxDataKey, MAX_DATA_REMAINING);
68                  }}).intValue() * 1024;
69          MAX_DATA_REMAINING = maxData;
70  
71          final String maxCapacityKey = "http.KeepAlive.queuedConnections";
72          int maxCapacity = AccessController.doPrivileged(
73              new PrivilegedAction<Integer>() {
74                  public Integer run() {
75                      return NetProperties.getInteger(maxCapacityKey, MAX_CAPACITY);
76                  }}).intValue();
77          MAX_CAPACITY = maxCapacity;
78  
79      }
80  
81  
82      @Override
83      public boolean offer(KeepAliveCleanerEntry e) {
84          if (size() >= MAX_CAPACITY)
85              return false;
86  
87          return super.offer(e);
88      }
89  
90      @Override
91      public void run()
92      {
93          KeepAliveCleanerEntry kace = null;
94  
95          do {
96              try {
97                  synchronized(this) {
98                      long before = System.currentTimeMillis();
99                      long timeout = TIMEOUT;
100                     while ((kace = poll()) == null) {
101                         this.wait(timeout);
102 
103                         long after = System.currentTimeMillis();
104                         long elapsed = after - before;
105                         if (elapsed > timeout) {
106                             /* one last try */
107                             kace = poll();
108                             break;
109                         }
110                         before = after;
111                         timeout -= elapsed;
112                     }
113                 }
114 
115                 if(kace == null)
116                     break;
117 
118                 KeepAliveStream kas = kace.getKeepAliveStream();
119 
120                 if (kas != null) {
121                     synchronized(kas) {
122                         HttpClient hc = kace.getHttpClient();
123                         try {
124                             if (hc != null && !hc.isInKeepAliveCache()) {
125                                 int oldTimeout = hc.getReadTimeout();
126                                 hc.setReadTimeout(TIMEOUT);
127                                 long remainingToRead = kas.remainingToRead();
128                                 if (remainingToRead > 0) {
129                                     long n = 0;
130                                     int retries = 0;
131                                     while (n < remainingToRead && retries < MAX_RETRIES) {
132                                         remainingToRead = remainingToRead - n;
133                                         n = kas.skip(remainingToRead);
134                                         if (n == 0)
135                                             retries++;
136                                     }
137                                     remainingToRead = remainingToRead - n;
138                                 }
139                                 if (remainingToRead == 0) {
140                                     hc.setReadTimeout(oldTimeout);
141                                     hc.finished();
142                                 } else
143                                     hc.closeServer();
144                             }
145                         } catch (IOException ioe) {
146                             hc.closeServer();
147                         } finally {
148                             kas.setClosed();
149                         }
150                     }
151                 }
152             } catch (InterruptedException ie) { }
153         } while (kace != null);
154     }
155 }