| 1214 | |
| 1215 | |
| 1216 | class StandardStreamInputBuffer extends StreamInputBuffer { |
| 1217 | |
| 1218 | private final Lock readStateLock = new ReentrantLock(); |
| 1219 | /* |
| 1220 | * Two buffers are required to avoid various multi-threading issues. These issues arise from the fact that the |
| 1221 | * Stream (or the Request/Response) used by the application is processed in one thread but the connection is |
| 1222 | * processed in another. Therefore it is possible that a request body frame could be received before the |
| 1223 | * application is ready to read it. If it isn't buffered, processing of the connection (and hence all streams) |
| 1224 | * would block until the application read the data. Hence the incoming data has to be buffered. If only one |
| 1225 | * buffer was used then it could become corrupted if the connection thread is trying to add to it at the same |
| 1226 | * time as the application is read it. While it should be possible to avoid this corruption by careful use of |
| 1227 | * the buffer it would still require the same copies as using two buffers and the behaviour would be less clear. |
| 1228 | * |
| 1229 | * The buffers are created lazily because they quickly add up to a lot of memory and most requests do not have |
| 1230 | * bodies. |
| 1231 | */ |
| 1232 | // This buffer is used to populate the ByteChunk passed in to the read |
| 1233 | // method |
| 1234 | private byte[] outBuffer; |
| 1235 | // This buffer is the destination for incoming data. It is normally is |
| 1236 | // 'write mode'. |
| 1237 | private volatile ByteBuffer inBuffer; |
| 1238 | private volatile boolean readInterest; |
| 1239 | // If readInterest is true, data must be available to read no later than this time. |
| 1240 | private volatile long readTimeoutExpiry; |
| 1241 | private volatile boolean closed; |
| 1242 | private volatile boolean resetReceived; |
| 1243 | |
| 1244 | @Override |
| 1245 | public final int doRead(ApplicationBufferHandler applicationBufferHandler) throws IOException { |
| 1246 | |
| 1247 | ensureBuffersExist(); |
| 1248 | |
| 1249 | int written; |
| 1250 | |
| 1251 | // It is still possible that the stream has been closed and inBuffer |
| 1252 | // set to null between the call to ensureBuffersExist() above and |
| 1253 | // the sync below. The checks just before and just inside the sync |
| 1254 | // ensure we don't get any NPEs reported. |
| 1255 | ByteBuffer tmpInBuffer = inBuffer; |
| 1256 | if (tmpInBuffer == null) { |
| 1257 | return -1; |
| 1258 | } |
| 1259 | // Ensure that only one thread accesses inBuffer at a time |
| 1260 | synchronized (tmpInBuffer) { |
| 1261 | if (inBuffer == null) { |
| 1262 | return -1; |
| 1263 | } |
| 1264 | boolean canRead = false; |
| 1265 | while (inBuffer.position() == 0 && (canRead = isActive() && !isInputFinished())) { |
| 1266 | // Need to block until some data is written |
| 1267 | try { |
| 1268 | if (log.isTraceEnabled()) { |
| 1269 | log.trace(sm.getString("stream.inputBuffer.empty")); |
| 1270 | } |
| 1271 | |
| 1272 | long readTimeout = handler.getProtocol().getStreamReadTimeout(); |
| 1273 | if (readTimeout < 0) { |
nothing calls this directly
no outgoing calls
no test coverage detected