@@ -515,7 +515,7 @@ public String getMessage() {
515515 @ PUT
516516 @ Consumes ("*/*" )
517517 @ Produces ("text/xml" )
518- public StreamingOutput getXhtml (final InputStream is , @ Context HttpHeaders httpHeaders )
518+ public Response getXhtml (final InputStream is , @ Context HttpHeaders httpHeaders )
519519 throws IOException {
520520 TikaInputStream tis = TikaInputStream .get (is );
521521 tis .getPath (); // Spool to temp file for pipes-based parsing
@@ -530,7 +530,7 @@ public StreamingOutput getXhtml(final InputStream is, @Context HttpHeaders httpH
530530 @ Consumes ("*/*" )
531531 @ Produces ("text/plain" )
532532 @ Path ("text" )
533- public StreamingOutput getText (final InputStream is , @ Context HttpHeaders httpHeaders )
533+ public Response getText (final InputStream is , @ Context HttpHeaders httpHeaders )
534534 throws IOException {
535535 TikaInputStream tis = TikaInputStream .get (is );
536536 tis .getPath (); // Spool to temp file for pipes-based parsing
@@ -545,7 +545,7 @@ public StreamingOutput getText(final InputStream is, @Context HttpHeaders httpHe
545545 @ Consumes ("*/*" )
546546 @ Produces ("text/html" )
547547 @ Path ("html" )
548- public StreamingOutput getHtml (final InputStream is , @ Context HttpHeaders httpHeaders )
548+ public Response getHtml (final InputStream is , @ Context HttpHeaders httpHeaders )
549549 throws IOException {
550550 TikaInputStream tis = TikaInputStream .get (is );
551551 tis .getPath (); // Spool to temp file for pipes-based parsing
@@ -560,7 +560,7 @@ public StreamingOutput getHtml(final InputStream is, @Context HttpHeaders httpHe
560560 @ Consumes ("*/*" )
561561 @ Produces ("text/xml" )
562562 @ Path ("xml" )
563- public StreamingOutput getXml (final InputStream is , @ Context HttpHeaders httpHeaders )
563+ public Response getXml (final InputStream is , @ Context HttpHeaders httpHeaders )
564564 throws IOException {
565565 TikaInputStream tis = TikaInputStream .get (is );
566566 tis .getPath (); // Spool to temp file for pipes-based parsing
@@ -575,7 +575,7 @@ public StreamingOutput getXml(final InputStream is, @Context HttpHeaders httpHea
575575 @ Consumes ("*/*" )
576576 @ Produces ("text/plain" )
577577 @ Path ("md" )
578- public StreamingOutput getMarkdown (final InputStream is , @ Context HttpHeaders httpHeaders )
578+ public Response getMarkdown (final InputStream is , @ Context HttpHeaders httpHeaders )
579579 throws IOException {
580580 TikaInputStream tis = TikaInputStream .get (is );
581581 tis .getPath (); // Spool to temp file for pipes-based parsing
@@ -634,7 +634,7 @@ public Metadata getJson(final InputStream is, @Context HttpHeaders httpHeaders,
634634 @ Consumes ("multipart/form-data" )
635635 @ Produces ("text/xml" )
636636 @ Path ("config" )
637- public StreamingOutput postRaw (List <Attachment > attachments , @ Context HttpHeaders httpHeaders )
637+ public Response postRaw (List <Attachment > attachments , @ Context HttpHeaders httpHeaders )
638638 throws IOException , TikaConfigException {
639639 ParseContext context = createParseContext ();
640640 Metadata metadata = Metadata .newInstance (context );
@@ -657,7 +657,7 @@ public StreamingOutput postRaw(List<Attachment> attachments, @Context HttpHeader
657657 @ Consumes ("multipart/form-data" )
658658 @ Produces ("text/plain" )
659659 @ Path ("config/text" )
660- public StreamingOutput postText (List <Attachment > attachments , @ Context HttpHeaders httpHeaders )
660+ public Response postText (List <Attachment > attachments , @ Context HttpHeaders httpHeaders )
661661 throws IOException , TikaConfigException {
662662 ParseContext context = createParseContext ();
663663 Metadata metadata = Metadata .newInstance (context );
@@ -679,7 +679,7 @@ public StreamingOutput postText(List<Attachment> attachments, @Context HttpHeade
679679 @ Consumes ("multipart/form-data" )
680680 @ Produces ("text/html" )
681681 @ Path ("config/html" )
682- public StreamingOutput postHtml (List <Attachment > attachments , @ Context HttpHeaders httpHeaders )
682+ public Response postHtml (List <Attachment > attachments , @ Context HttpHeaders httpHeaders )
683683 throws IOException , TikaConfigException {
684684 ParseContext context = createParseContext ();
685685 Metadata metadata = Metadata .newInstance (context );
@@ -701,7 +701,7 @@ public StreamingOutput postHtml(List<Attachment> attachments, @Context HttpHeade
701701 @ Consumes ("multipart/form-data" )
702702 @ Produces ("text/xml" )
703703 @ Path ("config/xml" )
704- public StreamingOutput postXml (List <Attachment > attachments , @ Context HttpHeaders httpHeaders )
704+ public Response postXml (List <Attachment > attachments , @ Context HttpHeaders httpHeaders )
705705 throws IOException , TikaConfigException {
706706 ParseContext context = createParseContext ();
707707 Metadata metadata = Metadata .newInstance (context );
@@ -723,7 +723,7 @@ public StreamingOutput postXml(List<Attachment> attachments, @Context HttpHeader
723723 @ Consumes ("multipart/form-data" )
724724 @ Produces ("text/plain" )
725725 @ Path ("config/md" )
726- public StreamingOutput postMarkdown (List <Attachment > attachments , @ Context HttpHeaders httpHeaders )
726+ public Response postMarkdown (List <Attachment > attachments , @ Context HttpHeaders httpHeaders )
727727 throws IOException , TikaConfigException {
728728 ParseContext context = createParseContext ();
729729 Metadata metadata = Metadata .newInstance (context );
@@ -760,7 +760,7 @@ public Metadata postJson(List<Attachment> attachments, @Context HttpHeaders http
760760 /**
761761 * Produces raw streaming output (text, html, xml, md) using pipes-based parsing.
762762 */
763- private StreamingOutput produceRawOutput (TikaInputStream tis , Metadata metadata ,
763+ private Response produceRawOutput (TikaInputStream tis , Metadata metadata ,
764764 MultivaluedMap <String , String > httpHeaders ,
765765 String handlerTypeName ) throws IOException {
766766 fillMetadata (null , metadata , httpHeaders );
@@ -771,8 +771,11 @@ private StreamingOutput produceRawOutput(TikaInputStream tis, Metadata metadata,
771771
772772 /**
773773 * Produces raw streaming output with a pre-configured ParseContext (for PUT endpoints).
774+ * A container-level parse exception doesn't discard content already captured -- status
775+ * is 422 (no field to embed the exception in, unlike the JSON endpoints), but the body
776+ * still carries whatever content was actually extracted.
774777 */
775- private StreamingOutput produceRawOutputWithContext (TikaInputStream tis , Metadata metadata ,
778+ private Response produceRawOutputWithContext (TikaInputStream tis , Metadata metadata ,
776779 ParseContext context ,
777780 String handlerTypeName ) throws IOException {
778781 logRequest (LOG , "/tika" , metadata );
@@ -794,42 +797,45 @@ private StreamingOutput produceRawOutputWithContext(TikaInputStream tis, Metadat
794797
795798 LOG .debug ("produceRawOutput: parseWithPipes returned {} metadata objects" , metadataList .size ());
796799
797- // For raw streaming endpoints, throw exception if there was a parse error
798- // (JSON endpoints return exceptions in metadata)
799- // Note: CONTAINER_EXCEPTION is extracted before the metadata filter runs,
800- // so it's available in the passback even though the filter strips it
801- if (!metadataList .isEmpty ()) {
802- String exception = metadataList .get (0 ).get (TikaCoreProperties .CONTAINER_EXCEPTION );
803- if (exception != null && !exception .isEmpty ()) {
804- LOG .debug ("produceRawOutput: parse exception: {}" , exception );
805- // Wrap in TikaException so TikaServerParseExceptionMapper returns 422
806- throw new TikaServerParseException (new TikaException (exception ));
807- }
808- }
809-
810- // Extract content from result
800+ // Extract content before checking for an exception -- content must not be
801+ // discarded just because a container-level exception also occurred.
811802 String content = "" ;
803+ boolean hasException = false ;
804+ String exceptionMessage = null ;
812805 if (!metadataList .isEmpty ()) {
813806 String extracted = metadataList .get (0 ).get (TikaCoreProperties .TIKA_CONTENT );
814807 LOG .debug ("produceRawOutput: TIKA_CONTENT length={}" , extracted != null ? extracted .length () : 0 );
815808 if (extracted != null ) {
816809 content = extracted ;
817810 }
811+ exceptionMessage = metadataList .get (0 ).get (TikaCoreProperties .CONTAINER_EXCEPTION );
812+ hasException = exceptionMessage != null && !exceptionMessage .isEmpty ();
813+ if (hasException ) {
814+ LOG .debug ("produceRawOutput: parse exception: {}" , exceptionMessage );
815+ }
816+ }
817+ // No separate field for the exception here, unlike JSON bodies -- append it,
818+ // gated by returnStackTrace like TikaServerParseExceptionMapper.
819+ if (hasException && pipesParsingHelper != null && pipesParsingHelper .isReturnStackTrace ()) {
820+ content = content .isEmpty () ? exceptionMessage : content + "\n " + exceptionMessage ;
818821 }
819822 final String finalContent = content ;
820823
821- return outputStream -> {
824+ StreamingOutput streamingOutput = outputStream -> {
822825 try (Writer writer = new OutputStreamWriter (outputStream , UTF_8 )) {
823826 writer .write (finalContent );
824827 writer .flush ();
825828 }
826829 };
830+ return Response .status (hasException ? 422 : Response .Status .OK .getStatusCode ())
831+ .entity (streamingOutput )
832+ .build ();
827833 }
828834
829835 /**
830836 * Produces raw streaming output with a pre-configured ParseContext (for POST endpoints).
831837 */
832- private StreamingOutput produceRawOutput (TikaInputStream tis , Metadata metadata ,
838+ private Response produceRawOutput (TikaInputStream tis , Metadata metadata ,
833839 ParseContext context ,
834840 String handlerTypeName ) throws IOException {
835841 return produceRawOutputWithContext (tis , metadata , context , handlerTypeName );
0 commit comments