@@ -81,8 +81,7 @@ public void write(int i) throws IOException {
81
81
try {
82
82
ob .writeByte (i );
83
83
} catch (IOException ioe ) {
84
- ob .setErrorException (ioe );
85
- throw ioe ;
84
+ handleIOException (ioe );
86
85
}
87
86
if (nonBlocking ) {
88
87
checkRegisterForWrite ();
@@ -102,8 +101,7 @@ public void write(byte[] b, int off, int len) throws IOException {
102
101
try {
103
102
ob .write (b , off , len );
104
103
} catch (IOException ioe ) {
105
- ob .setErrorException (ioe );
106
- throw ioe ;
104
+ handleIOException (ioe );
107
105
}
108
106
if (nonBlocking ) {
109
107
checkRegisterForWrite ();
@@ -121,8 +119,7 @@ public void write(ByteBuffer from) throws IOException {
121
119
try {
122
120
ob .write (from );
123
121
} catch (IOException ioe ) {
124
- ob .setErrorException (ioe );
125
- throw ioe ;
122
+ handleIOException (ioe );
126
123
}
127
124
if (nonBlocking ) {
128
125
checkRegisterForWrite ();
@@ -139,8 +136,7 @@ public void flush() throws IOException {
139
136
try {
140
137
ob .flush ();
141
138
} catch (IOException ioe ) {
142
- ob .setErrorException (ioe );
143
- throw ioe ;
139
+ handleIOException (ioe );
144
140
}
145
141
if (nonBlocking ) {
146
142
checkRegisterForWrite ();
@@ -179,8 +175,7 @@ public void close() throws IOException {
179
175
try {
180
176
ob .close ();
181
177
} catch (IOException ioe ) {
182
- ob .setErrorException (ioe );
183
- throw ioe ;
178
+ handleIOException (ioe );
184
179
}
185
180
}
186
181
@@ -197,5 +192,29 @@ public boolean isReady() {
197
192
public void setWriteListener (WriteListener listener ) {
198
193
ob .setWriteListener (listener );
199
194
}
195
+
196
+
197
+ private void handleIOException (IOException ioe ) throws IOException {
198
+ try {
199
+ ob .setErrorException (ioe );
200
+ } catch (NullPointerException npe ) {
201
+ /*
202
+ * Ignore.
203
+ *
204
+ * An IOException on a non-container thread during asynchronous Servlet processing will trigger a dispatch
205
+ * to a container thread that will complete the asynchronous processing and recycle the request, response
206
+ * and associated objects including the OutputBuffer. Depending on timing it is possible that the
207
+ * OutputBuffer will have been cleared by the time the call above is made - resulting in an NPE.
208
+ *
209
+ * If the OutputBuffer is null then there is no need to call setErrorException(). Catching and ignoring the
210
+ * NPE is (for now at least) a simpler solution than adding locking to OutputBuffer to ensure it is non-null
211
+ * and remains non-null while setErrorException() is called.
212
+ *
213
+ * The longer term solution is likely a refactoring and clean-up of error handling for asynchronous requests
214
+ * but that is potentially a significant piece of work.
215
+ */
216
+ }
217
+ throw ioe ;
218
+ }
200
219
}
201
220
0 commit comments