Skip to content

Commit a361cab

Browse files
committed
if nothing happens with the capture - no header or status set - should report as handled
- weird yet works with Tomcat as before and serves static content with Jetty right again - make sure when asked and reported isHandled as truthy it stays (due the container) - also do some internal cleanup - whole output swalowing should get a review ... fixes #175
1 parent 12797eb commit a361cab

File tree

2 files changed

+51
-37
lines changed

2 files changed

+51
-37
lines changed

src/main/java/org/jruby/rack/servlet/ResponseCapture.java

Lines changed: 34 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@
88
package org.jruby.rack.servlet;
99

1010
import java.io.IOException;
11-
import java.io.OutputStream;
1211
import java.io.OutputStreamWriter;
1312
import java.io.PrintWriter;
1413
import java.lang.reflect.InvocationTargetException;
@@ -65,11 +64,11 @@ public boolean isStatusSet() {
6564
*
6665
* @param status the new HTTP status
6766
* @param error whether the status comes from a {@code sendError}
68-
* @see #isHandled()
67+
* @see #isHandled(HttpServletRequest)
6968
*/
7069
protected boolean handleStatus(int status, boolean error) {
7170
this.status = status;
72-
return isHandled();
71+
return isHandled(null);
7372
}
7473

7574
@Override
@@ -157,11 +156,9 @@ public void setIntHeader(String name, int value) {
157156
public ServletOutputStream getOutputStream() throws IOException {
158157
if ( output == null ) output = STREAM;
159158

160-
if ( isHandled() ) {
161-
return super.getOutputStream();
162-
}
163-
else {
164-
// backwards compatibility with isError() then :
159+
if ( isHandled(null) ) return super.getOutputStream();
160+
else { // TODO get rid of this in 1.2.0
161+
// backwards compatibility with isError() :
165162
return new ServletOutputStream() {
166163
@Override
167164
public void write(int b) throws IOException {
@@ -175,43 +172,37 @@ public void write(int b) throws IOException {
175172
public PrintWriter getWriter() throws IOException {
176173
if ( output == null ) output = WRITER;
177174

178-
if ( isHandled() ) {
179-
// we protect against API limitations as we depend on #getWriter
180-
// being functional even if getOutputStream has been called ...
181-
if ( output != WRITER ) {
182-
String enc = getCharacterEncoding();
183-
if ( enc == null ) enc = "UTF-8";
184-
return new PrintWriter(new OutputStreamWriter(getOutputStream(), enc));
185-
}
186-
else {
187-
return super.getWriter();
188-
}
175+
// we protect against API limitations as we depend on #getWriter
176+
// being functional even if getOutputStream has been called ...
177+
if ( output != WRITER ) {
178+
String enc = getCharacterEncoding();
179+
if ( enc == null ) enc = "UTF-8";
180+
return new PrintWriter(new OutputStreamWriter(getOutputStream(), enc));
189181
}
190182
else {
191-
// backwards compatibility with isError() then :
192-
return new PrintWriter(new OutputStream() {
193-
@Override
194-
public void write(int b) throws IOException {
195-
// swallow output, because we're going to discard it
196-
}
197-
});
183+
return super.getWriter();
198184
}
199185
}
200186

201187
@Override
202188
public void flushBuffer() throws IOException {
203-
if ( isHandled() ) super.flushBuffer();
189+
if ( isHandled(null) ) super.flushBuffer();
204190
}
205191

206192
public boolean isError() {
207193
return getStatus() >= 400;
208194
}
209195

210-
// NOTE: should probably deprecate this one
196+
/**
197+
* @deprecated no longer to be used from outside
198+
* @see #isHandled(HttpServletRequest)
199+
*/
211200
public boolean isHandled() {
212201
return isHandled(null);
213202
}
214203

204+
private boolean handled; // once handled - stays handled
205+
215206
/**
216207
* Response is considered to be handled if a status has been set
217208
* and it is (by default) not a HTTP NOT FOUND (404) status.
@@ -220,28 +211,36 @@ public boolean isHandled() {
220211
* @see #handleStatus(int, boolean)
221212
*/
222213
public boolean isHandled(final HttpServletRequest request) {
214+
if ( handled ) return true; // ... once handled always handled !
215+
223216
// setting a header should consider the response to be handled
224217
if ( ! isStatusSet() ) {
225-
if ( ! isHeaderSet() ) return false;
218+
if ( ! isHeaderSet() ) {
219+
// true by default seems very weird but this is best to cover
220+
// "more" containers right out of the box ...
221+
// e.g. Jetty https://github.com/jruby/jruby-rack/issues/175
222+
return handled = true; // return false;
223+
}
226224

227225
// consider HTTP OPTIONS with "Allow" header unhandled :
228226
if ( request != null && "OPTIONS".equals( request.getMethod() ) ) {
229-
final Collection<String> headerNames = getHeaderNamesInternal();
227+
final Collection<String> headerNames = getHeaderNamesOrNull();
230228
if ( headerNames == null || headerNames.isEmpty() ) {
231229
// not to happen but there's all kind of beasts out there
232230
return false;
233231
}
234232
for ( final String headerName : headerNames ) {
235233
if ( ! "Allow".equals(headerName) ) {
236-
return true; // not just Allow header - consider handled
234+
return handled = true; // not just Allow header - consider handled
237235
}
238236
}
239237
return false; // OPTIONS with only Allow header set - unhandled
240238
}
241-
return true;
239+
return handled = true;
242240
}
241+
243242
if ( notHandledStatuses.contains( getStatus() ) ) return false;
244-
return true;
243+
return handled = true;
245244
}
246245

247246
public Collection<Integer> getNotHandledStatuses() {
@@ -263,8 +262,8 @@ public boolean isOutputAccessed() {
263262
}
264263

265264
@SuppressWarnings("unchecked")
266-
private Collection<String> getHeaderNamesInternal() {
267-
// NOTE: getHeaderNames available since 3.0 JRuby-Rack 1.1 still support 2.5
265+
private Collection<String> getHeaderNamesOrNull() {
266+
// NOTE: getHeaderNames since Servlet API 3.0 JRuby-Rack 1.1 still supports 2.5
268267
try {
269268
final Method getHeaderNames = HttpServletResponse.class.getMethod("getHeaderNames");
270269
return (Collection<String>) getHeaderNames.invoke(this);

src/spec/ruby/rack/servlet/response_capture_spec.rb

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,14 @@
2121
expect( response_capture.isOutputAccessed ).to be true
2222
end
2323

24+
it "is considered handled by default" do
25+
# NOTE: weird but this is what some containers need to e.g. serve
26+
# static content with RackFilter correctly (e.g. Jetty)
27+
expect( response_capture.isHandled ).to be true
28+
end
29+
2430
it "is not considered handled by default or when 404 set" do
25-
expect( response_capture.isHandled ).to be false
31+
#expect( response_capture.isHandled ).to be false
2632

2733
response_capture.setStatus(404)
2834
expect( response_capture.isHandled ).to be false
@@ -37,10 +43,19 @@
3743
expect( response_capture.isHandled ).to be true
3844
end
3945

46+
it "once considered handled stays handled" do
47+
response_capture.setStatus(200)
48+
expect( response_capture.isHandled ).to be true
49+
# NOTE: quite important since container might have accessed and written to
50+
# the real output-stream already ... status change should not happen though
51+
response_capture.setStatus(404)
52+
expect( response_capture.isHandled ).to be true
53+
end
54+
4055
it "is not considered handled when only Allow header is added with OPTIONS" do
4156
servlet_request.method = 'OPTIONS'
4257

43-
expect( response_capture.isHandled(servlet_request) ).to be false
58+
#expect( response_capture.isHandled(servlet_request) ).to be false
4459

4560
# NOTE: this is what TC's DefaultServlet does on doOptions() :
4661
response_capture.addHeader "Allow", "GET, POST, OPTIONS"

0 commit comments

Comments
 (0)