2020import java .io .BufferedWriter ;
2121import java .io .IOException ;
2222import java .io .OutputStream ;
23+ import java .io .Writer ;
2324import java .util .ArrayList ;
2425import java .util .Collection ;
2526import java .util .List ;
2627import java .util .Map ;
2728import java .util .Optional ;
2829import java .util .TreeMap ;
2930import javax .servlet .http .HttpServletResponse ;
31+ import org .eclipse .jetty .util .IO ;
3032
3133public class HttpResponseImpl implements HttpResponse {
3234 private final HttpServletResponse response ;
@@ -43,7 +45,7 @@ public void setStatusCode(int code) {
4345 @ Override
4446 @ SuppressWarnings ("deprecation" )
4547 public void setStatusCode (int code , String message ) {
46- response .setStatus (code , message );
48+ response .setStatus (code );
4749 }
4850
4951 @ Override
@@ -86,32 +88,92 @@ public OutputStream getOutputStream() throws IOException {
8688 @ Override
8789 public synchronized BufferedWriter getWriter () throws IOException {
8890 if (writer == null ) {
89- // Unfortunately this means that we get two intermediate objects between the object we return
90- // and the underlying Writer that response.getWriter() wraps. We could try accessing the
91- // PrintWriter.out field via reflection, but that sort of access to non-public fields of
92- // platform classes is now frowned on and may draw warnings or even fail in subsequent
93- // versions. We could instead wrap the OutputStream, but that would require us to deduce the
94- // appropriate Charset, using logic like this:
95- // https://github.com/eclipse/jetty.project/blob/923ec38adf/jetty-server/src/main/java/org/eclipse/jetty/server/Response.java#L731
96- // We may end up doing that if performance is an issue.
97- writer = new BufferedWriter (response .getWriter ());
91+ writer = new NonBufferedWriter (response .getWriter ());
9892 }
9993 return writer ;
10094 }
10195
102- public void flush () {
96+ /** Close the response, flushing all content. */
97+ public void close () {
10398 try {
104- // We can't use HttpServletResponse.flushBuffer() because we wrap the
105- // PrintWriter returned by HttpServletResponse in our own BufferedWriter
106- // to match our API. So we have to flush whichever of getWriter() or
107- // getOutputStream() works.
99+ IO .close (getOutputStream ());
100+ } catch (IllegalStateException | IOException e ) {
108101 try {
109- getOutputStream (). flush ( );
110- } catch (IllegalStateException e ) {
111- getWriter (). flush ();
102+ IO . close ( getWriter () );
103+ } catch (IOException ioe ) {
104+ // Too bad, can't close.
112105 }
113- } catch (IOException e ) {
114- // Too bad, can't flush.
106+ }
107+ }
108+
109+ /**
110+ * A {@link BufferedWriter} that does not buffer. It is generally more efficient to buffer at the
111+ * lower level, since frequently total content is smaller than a single buffer and the lower level
112+ * buffer can turn a close into a last write that will avoid chunking the response if at all
113+ * possible. However, {@link BufferedWriter} is in the API for {@link HttpResponse}, so we must
114+ * return a writer of that type.
115+ */
116+ private static class NonBufferedWriter extends BufferedWriter {
117+ private final Writer writer ;
118+
119+ public NonBufferedWriter (Writer out ) {
120+ super (out , 1 );
121+ writer = out ;
122+ }
123+
124+ @ Override
125+ public void write (int c ) throws IOException {
126+ writer .write (c );
127+ }
128+
129+ @ Override
130+ public void write (char [] cbuf ) throws IOException {
131+ writer .write (cbuf );
132+ }
133+
134+ @ Override
135+ public void write (char [] cbuf , int off , int len ) throws IOException {
136+ writer .write (cbuf , off , len );
137+ }
138+
139+ @ Override
140+ public void write (String str ) throws IOException {
141+ writer .write (str );
142+ }
143+
144+ @ Override
145+ public void write (String str , int off , int len ) throws IOException {
146+ writer .write (str , off , len );
147+ }
148+
149+ @ Override
150+ public Writer append (CharSequence csq ) throws IOException {
151+ return writer .append (csq );
152+ }
153+
154+ @ Override
155+ public Writer append (CharSequence csq , int start , int end ) throws IOException {
156+ return writer .append (csq , start , end );
157+ }
158+
159+ @ Override
160+ public Writer append (char c ) throws IOException {
161+ return writer .append (c );
162+ }
163+
164+ @ Override
165+ public void flush () throws IOException {
166+ writer .flush ();
167+ }
168+
169+ @ Override
170+ public void close () throws IOException {
171+ writer .close ();
172+ }
173+
174+ @ Override
175+ public void newLine () throws IOException {
176+ writer .write (System .lineSeparator ());
115177 }
116178 }
117179}
0 commit comments