111111
112112import jakarta .servlet .http .HttpServletRequest ;
113113import jakarta .servlet .http .HttpServletResponse ;
114+
115+ import javax .annotation .Nullable ;
114116import javax .xml .XMLConstants ;
115117import javax .xml .parsers .ParserConfigurationException ;
116118import javax .xml .stream .XMLStreamException ;
@@ -1851,14 +1853,22 @@ private void writeResourceAs(final DocumentImpl resource, final DBBroker broker,
18511853 outputProperties .setProperty ("omit-xml-declaration" , "no" );
18521854 }
18531855
1854- final OutputStreamWriter writer = new OutputStreamWriter (response .getOutputStream (), encoding );
1855- sax .setOutput (writer , outputProperties );
1856- serializer .setSAXHandlers (sax , sax );
1856+ // NOTE(AR) we only close the OutputStreamWriter if serialization succeeds, otherwise we raise a BadRequestException below which needs the OutputStream to remain open so that it can report the issue via the HTTP response to the client
1857+ @ Nullable Writer writerToClose = null ;
1858+ try {
1859+ final Writer writer = new OutputStreamWriter (response .getOutputStream (), encoding );
1860+ sax .setOutput (writer , outputProperties );
1861+ serializer .setSAXHandlers (sax , sax );
18571862
1858- serializer .toSAX (resource );
1863+ serializer .toSAX (resource );
18591864
1860- writer .flush ();
1861- writer .close (); // DO NOT use in try-write-resources, otherwise ther response stream is always closed, and we can't report the errors
1865+ writer .flush ();
1866+ writerToClose = writer ;
1867+ } finally {
1868+ if (writerToClose != null ) {
1869+ writerToClose .close ();
1870+ }
1871+ }
18621872 } catch (final SAXException saxe ) {
18631873 LOG .warn (saxe );
18641874 throw new BadRequestException ("Error while serializing XML: " + saxe .getMessage ());
@@ -1894,28 +1904,36 @@ private void writeXPathExceptionHtml(final HttpServletResponse response,
18941904
18951905 response .setContentType (MimeType .HTML_TYPE .getName () + "; charset=" + encoding );
18961906
1897- final OutputStreamWriter writer = new OutputStreamWriter (response .getOutputStream (), encoding );
1898- writer .write (QUERY_ERROR_HEAD );
1899- writer .write ("<p class=\" path\" ><span class=\" high\" >Path</span>: " );
1900- writer .write ("<a href=\" " );
1901- writer .write (path );
1902- writer .write ("\" >" );
1903- writer .write (path );
1904- writer .write ("</a>" );
1905-
1906- writer .write ("<p class=\" errmsg\" >" );
1907- final String message = e .getMessage () == null ? e .toString () : e .getMessage ();
1908- writer .write (XMLUtil .encodeAttrMarkup (message ));
1909- writer .write ("" );
1910- if (query != null ) {
1911- writer .write ("<span class=\" high\" >Query</span>:<pre>" );
1912- writer .write (XMLUtil .encodeAttrMarkup (query ));
1913- writer .write ("</pre>" );
1914- }
1915- writer .write ("</body></html>" );
1907+ // NOTE(AR) we only close the OutputStreamWriter if serialization succeeds, otherwise we raise a BadRequestException below which needs the OutputStream to remain open so that it can report the issue via the HTTP response to the client
1908+ @ Nullable Writer writerToClose = null ;
1909+ try {
1910+ final Writer writer = new OutputStreamWriter (response .getOutputStream (), encoding );
1911+ writer .write (QUERY_ERROR_HEAD );
1912+ writer .write ("<p class=\" path\" ><span class=\" high\" >Path</span>: " );
1913+ writer .write ("<a href=\" " );
1914+ writer .write (path );
1915+ writer .write ("\" >" );
1916+ writer .write (path );
1917+ writer .write ("</a>" );
19161918
1917- writer .flush ();
1918- writer .close ();
1919+ writer .write ("<p class=\" errmsg\" >" );
1920+ final String message = e .getMessage () == null ? e .toString () : e .getMessage ();
1921+ writer .write (XMLUtil .encodeAttrMarkup (message ));
1922+ writer .write ("" );
1923+ if (query != null ) {
1924+ writer .write ("<span class=\" high\" >Query</span>:<pre>" );
1925+ writer .write (XMLUtil .encodeAttrMarkup (query ));
1926+ writer .write ("</pre>" );
1927+ }
1928+ writer .write ("</body></html>" );
1929+
1930+ writer .flush ();
1931+ writerToClose = writer ;
1932+ } finally {
1933+ if (writerToClose != null ) {
1934+ writerToClose .close ();
1935+ }
1936+ }
19191937 }
19201938
19211939 /**
@@ -1937,8 +1955,10 @@ private void writeXPathException(final HttpServletResponse response,
19371955
19381956 response .setContentType (MimeType .XML_TYPE .getName () + "; charset=" + encoding );
19391957
1940- try (final OutputStreamWriter writer =
1941- new OutputStreamWriter (response .getOutputStream (), encoding )) {
1958+ // NOTE(AR) we only close the OutputStreamWriter if serialization succeeds, otherwise we raise a BadRequestException below which needs the OutputStream to remain open so that it can report the issue via the HTTP response to the client
1959+ @ Nullable Writer writerToClose = null ;
1960+ try {
1961+ final Writer writer = new OutputStreamWriter (response .getOutputStream (), encoding );
19421962
19431963 writer .write ("<?xml version=\" 1.0\" ?>" );
19441964 writer .write ("<exception><path>" );
@@ -1954,6 +1974,13 @@ private void writeXPathException(final HttpServletResponse response,
19541974 writer .write ("</query>" );
19551975 }
19561976 writer .write ("</exception>" );
1977+
1978+ writer .flush ();
1979+ writerToClose = writer ;
1980+ } finally {
1981+ if (writerToClose != null ) {
1982+ writerToClose .close ();
1983+ }
19571984 }
19581985 }
19591986
@@ -1971,17 +1998,23 @@ private void writeXUpdateResult(final HttpServletResponse response,
19711998
19721999 response .setContentType (MimeType .XML_TYPE .getName () + "; charset=" + encoding );
19732000
1974- final OutputStreamWriter writer =
1975- new OutputStreamWriter (response .getOutputStream (), encoding );
1976-
1977- writer .write ("<?xml version=\" 1.0\" ?>" );
1978- writer .write ("<exist:modifications xmlns:exist=\" "
2001+ // NOTE(AR) we only close the OutputStreamWriter if serialization succeeds, otherwise we raise a BadRequestException below which needs the OutputStream to remain open so that it can report the issue via the HTTP response to the client
2002+ @ Nullable Writer writerToClose = null ;
2003+ try {
2004+ final Writer writer = new OutputStreamWriter (response .getOutputStream (), encoding );
2005+ writer .write ("<?xml version=\" 1.0\" ?>" );
2006+ writer .write ("<exist:modifications xmlns:exist=\" "
19792007 + Namespaces .EXIST_NS + "\" count=\" " + updateCount + "\" >" );
1980- writer .write (updateCount + " modifications processed." );
1981- writer .write ("</exist:modifications>" );
2008+ writer .write (updateCount + " modifications processed." );
2009+ writer .write ("</exist:modifications>" );
19822010
1983- writer .flush ();
1984- writer .close ();
2011+ writer .flush ();
2012+ writerToClose = writer ;
2013+ } finally {
2014+ if (writerToClose != null ) {
2015+ writerToClose .close ();
2016+ }
2017+ }
19852018 }
19862019
19872020 /**
@@ -2004,12 +2037,12 @@ protected void writeCollection(final HttpServletResponse response,
20042037
20052038 setCreatedAndLastModifiedHeaders (response , collection .getCreated (), collection .getCreated ());
20062039
2007- final OutputStreamWriter writer =
2008- new OutputStreamWriter (response .getOutputStream (), encoding );
2009-
20102040 SAXSerializer serializer = null ;
20112041
2042+ // NOTE(AR) we only close the OutputStreamWriter if serialization succeeds, otherwise we raise a BadRequestException below which needs the OutputStream to remain open so that it can report the issue via the HTTP response to the client
2043+ @ Nullable Writer writerToClose = null ;
20122044 try {
2045+ final Writer writer = new OutputStreamWriter (response .getOutputStream (), encoding );
20132046 serializer = (SAXSerializer ) SerializerPool .getInstance ().borrowObject (SAXSerializer .class );
20142047
20152048 serializer .setOutput (writer , defaultProperties );
@@ -2109,7 +2142,7 @@ protected void writeCollection(final HttpServletResponse response,
21092142 serializer .endDocument ();
21102143
21112144 writer .flush ();
2112- writer . close () ;
2145+ writerToClose = writer ;
21132146
21142147 } catch (final SAXException e ) {
21152148 // should never happen
@@ -2118,6 +2151,9 @@ protected void writeCollection(final HttpServletResponse response,
21182151 if (serializer != null ) {
21192152 SerializerPool .getInstance ().returnObject (serializer );
21202153 }
2154+ if (writerToClose != null ) {
2155+ writerToClose .close ();
2156+ }
21212157 }
21222158 }
21232159
@@ -2193,14 +2229,23 @@ private void writeResultXML(final HttpServletResponse response,
21932229 if (wrap ) {
21942230 outputProperties .setProperty ("method" , "xml" );
21952231 }
2196- final Writer writer = new OutputStreamWriter (response .getOutputStream (), encoding );
2197- final XQuerySerializer serializer = new XQuerySerializer (broker , outputProperties , writer );
21982232
2199- //Marshaller.marshall(broker, results, start, howmany, serializer.getContentHandler());
2200- serializer .serialize (results , start , howmany , wrap , typed , compilationTime , executionTime );
2233+ // NOTE(AR) we only close the OutputStreamWriter if serialization succeeds, otherwise we raise a BadRequestException below which needs the OutputStream to remain open so that it can report the issue via the HTTP response to the client
2234+ @ Nullable Writer writerToClose = null ;
2235+ try {
2236+ final Writer writer = new OutputStreamWriter (response .getOutputStream (), encoding );
2237+ final XQuerySerializer serializer = new XQuerySerializer (broker , outputProperties , writer );
22012238
2202- writer .flush ();
2203- writer .close ();
2239+ //Marshaller.marshall(broker, results, start, howmany, serializer.getContentHandler());
2240+ serializer .serialize (results , start , howmany , wrap , typed , compilationTime , executionTime );
2241+
2242+ writer .flush ();
2243+ writerToClose = writer ;
2244+ } finally {
2245+ if (writerToClose != null ) {
2246+ writerToClose .close ();
2247+ }
2248+ }
22042249
22052250 } catch (final SAXException e ) {
22062251 LOG .warn (e );
@@ -2236,7 +2281,9 @@ private void writeResultJSON(final HttpServletResponse response,
22362281 outputProperties .setProperty (Serializer .GENERATE_DOC_EVENTS , "false" );
22372282 try {
22382283 serializer .setProperties (outputProperties );
2239- try (final Writer writer = new OutputStreamWriter (response .getOutputStream (), getEncoding (outputProperties ))) {
2284+ @ Nullable Writer writerToClose = null ;
2285+ try {
2286+ final Writer writer = new OutputStreamWriter (response .getOutputStream (), getEncoding (outputProperties ));
22402287 final JSONObject root = new JSONObject ();
22412288 root .addObject (new JSONSimpleProperty ("start" , Integer .toString (start ), true ));
22422289 root .addObject (new JSONSimpleProperty ("count" , Integer .toString (howmany ), true ));
@@ -2280,6 +2327,12 @@ private void writeResultJSON(final HttpServletResponse response,
22802327 root .serialize (writer , true );
22812328
22822329 writer .flush ();
2330+ writerToClose = writer ;
2331+
2332+ } finally {
2333+ if (writerToClose != null ) {
2334+ writerToClose .close ();
2335+ }
22832336 }
22842337 } catch (final IOException | XPathException | SAXException e ) {
22852338 throw new BadRequestException ("Error while serializing xml: " + e .toString (), e );
0 commit comments