Skip to content

Commit b05669b

Browse files
authored
Merge pull request #1197 from baranowb/UNDERTOW-1359_v2
[UNDERTOW-1359] - fix concurrent change/access to buffer
2 parents bcb0849 + aa58e6b commit b05669b

File tree

1 file changed

+48
-29
lines changed

1 file changed

+48
-29
lines changed

core/src/main/java/io/undertow/server/protocol/framed/AbstractFramedStreamSourceChannel.java

Lines changed: 48 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -122,21 +122,31 @@ public long transferTo(long position, long count, FileChannel target) throws IOE
122122
return 0;
123123
}
124124
try {
125+
final PooledByteBuffer localData = data;
125126
if (frameDataRemaining == 0 && anyAreSet(state, STATE_LAST_FRAME)) {
126127
synchronized (lock) {
127128
state |= STATE_RETURNED_MINUS_ONE;
128129
return -1;
129130
}
130-
} else if (data != null) {
131-
int old = data.getBuffer().limit();
131+
} else if (localData != null) {
132132
try {
133-
if (count < data.getBuffer().remaining()) {
134-
data.getBuffer().limit((int) (data.getBuffer().position() + count));
133+
final int old = localData.getBuffer().limit();
134+
try {
135+
if (count < localData.getBuffer().remaining()) {
136+
localData.getBuffer().limit((int) (localData.getBuffer().position() + count));
137+
}
138+
return target.write(localData.getBuffer(), position);
139+
} finally {
140+
localData.getBuffer().limit(old);
141+
decrementFrameDataRemaining();
142+
}
143+
} catch (IllegalStateException e) {
144+
// NPE should be covered. ISE in case of closed buffer
145+
if (anyAreSet(state, STATE_DONE | STATE_CLOSED | STATE_STREAM_BROKEN)) {
146+
return -1;
147+
} else {
148+
throw e;
135149
}
136-
return target.write(data.getBuffer(), position);
137-
} finally {
138-
data.getBuffer().limit(old);
139-
decrementFrameDataRemaining();
140150
}
141151
}
142152
return 0;
@@ -146,7 +156,8 @@ public long transferTo(long position, long count, FileChannel target) throws IOE
146156
}
147157

148158
private void decrementFrameDataRemaining() {
149-
if(!data.getBuffer().hasRemaining()) {
159+
final PooledByteBuffer localData = data;
160+
if(localData != null && !localData.getBuffer().hasRemaining()) {
150161
frameDataRemaining -= currentDataOriginalSize;
151162
}
152163
}
@@ -162,36 +173,44 @@ public long transferTo(long count, ByteBuffer throughBuffer, StreamSinkChannel s
162173
return 0;
163174
}
164175
try {
176+
final PooledByteBuffer localData = data;
165177
if (frameDataRemaining == 0 && anyAreSet(state, STATE_LAST_FRAME)) {
166178
synchronized (lock) {
167179
state |= STATE_RETURNED_MINUS_ONE;
168180
return -1;
169181
}
170-
} else if (data != null && data.getBuffer().hasRemaining()) {
171-
int old = data.getBuffer().limit();
182+
} else if (localData != null && localData.getBuffer().hasRemaining()) {
183+
int old = localData.getBuffer().limit();
172184
try {
173-
if (count < data.getBuffer().remaining()) {
174-
data.getBuffer().limit((int) (data.getBuffer().position() + count));
185+
if (count < localData.getBuffer().remaining()) {
186+
localData.getBuffer().limit((int) (localData.getBuffer().position() + count));
175187
}
176-
int written = streamSinkChannel.write(data.getBuffer());
177-
if(data.getBuffer().hasRemaining()) {
188+
int written = streamSinkChannel.write(localData.getBuffer());
189+
if(localData.getBuffer().hasRemaining()) {
178190
//we can still add more data
179191
//stick it it throughbuffer, otherwise transfer code will continue to attempt to use this method
180192
throughBuffer.clear();
181-
Buffers.copy(throughBuffer, data.getBuffer());
193+
Buffers.copy(throughBuffer, localData.getBuffer());
182194
throughBuffer.flip();
183195
} else {
184196
throughBuffer.position(throughBuffer.limit());
185197
}
186198
return written;
187199
} finally {
188-
data.getBuffer().limit(old);
200+
localData.getBuffer().limit(old);
189201
decrementFrameDataRemaining();
190202
}
191203
} else {
192204
throughBuffer.position(throughBuffer.limit());
193205
}
194206
return 0;
207+
} catch (IllegalStateException e) {
208+
// NPE should be covered. ISE in case of closed buffer
209+
if (anyAreSet(state, STATE_DONE | STATE_CLOSED | STATE_STREAM_BROKEN)) {
210+
return -1;
211+
} else {
212+
throw e;
213+
}
195214
} finally {
196215
exitRead();
197216
}
@@ -589,29 +608,29 @@ private void beforeRead() throws IOException {
589608
}
590609

591610
private void exitRead() throws IOException {
592-
if (data != null && !data.getBuffer().hasRemaining()) {
593-
data.close();
594-
data = null;
595-
}
596-
if (frameDataRemaining == 0) {
597-
try {
598-
synchronized (lock) {
611+
synchronized (lock) {
612+
if (data != null && !data.getBuffer().hasRemaining()) {
613+
data.close();
614+
data = null;
615+
}
616+
if (frameDataRemaining == 0) {
617+
try {
599618
readFrameCount++;
600619
if (pendingFrameData.isEmpty()) {
601620
if (anyAreSet(state, STATE_RETURNED_MINUS_ONE)) {
602621
state |= STATE_DONE;
603622
complete();
604623
close();
605-
} else if(anyAreSet(state, STATE_LAST_FRAME)) {
624+
} else if (anyAreSet(state, STATE_LAST_FRAME)) {
606625
state |= STATE_WAITNG_MINUS_ONE;
607626
} else {
608627
waitingForFrame = true;
609628
}
610629
}
611-
}
612-
} finally {
613-
if (pendingFrameData.isEmpty()) {
614-
framedChannel.notifyFrameReadComplete(this);
630+
} finally {
631+
if (pendingFrameData.isEmpty()) {
632+
framedChannel.notifyFrameReadComplete(this);
633+
}
615634
}
616635
}
617636
}

0 commit comments

Comments
 (0)