1818
1919import static org .apache .tika .server .core .resource .TikaResource .fillMetadata ;
2020
21- import java .io .IOException ;
2221import java .io .InputStream ;
2322import java .util .List ;
2423
3736import org .slf4j .Logger ;
3837import org .slf4j .LoggerFactory ;
3938
40- import org .apache .tika .exception . TikaConfigException ;
41- import org .apache .tika .extractor . DocumentSelector ;
39+ import org .apache .tika .config . EmbeddedLimits ;
40+ import org .apache .tika .exception . TikaException ;
4241import org .apache .tika .io .TikaInputStream ;
43- import org .apache .tika .language .detect .LanguageHandler ;
4442import org .apache .tika .metadata .Metadata ;
43+ import org .apache .tika .metadata .TikaCoreProperties ;
4544import org .apache .tika .parser .ParseContext ;
46- import org .apache .tika .parser .Parser ;
45+ import org .apache .tika .pipes .api .ParseMode ;
46+ import org .apache .tika .sax .BasicContentHandlerFactory ;
47+ import org .apache .tika .sax .ContentHandlerFactory ;
48+ import org .apache .tika .server .core .TikaServerParseException ;
4749
4850
4951@ Path ("/meta" )
@@ -63,8 +65,9 @@ public MetadataResource(TikaResource tikaResource) {
6365 public Response getMetadataFromMultipart (Attachment att , @ Context UriInfo info ) throws Exception {
6466 ParseContext context = tikaResource .createParseContext ();
6567 try (TikaInputStream tis = TikaInputStream .get (att .getObject (InputStream .class ))) {
68+ tis .getPath (); // Spool to temp file for pipes-based parsing
6669 return Response
67- .ok (parseMetadata (tis , Metadata .newInstance (context ), att .getHeaders (), info ))
70+ .ok (parseMetadata (tis , Metadata .newInstance (context ), att .getHeaders (), context ))
6871 .build ();
6972 }
7073 }
@@ -79,25 +82,14 @@ public Response getMetadataFromMultipart(Attachment att, @Context UriInfo info)
7982 @ Path ("config" )
8083 public Response getMetadataWithConfig (
8184 List <Attachment > attachments ,
82- @ Context HttpHeaders httpHeaders ,
83- @ Context UriInfo info ) throws Exception {
85+ @ Context HttpHeaders httpHeaders ) throws Exception {
8486
8587 // Load default context from config, then overlay with request config
8688 ParseContext context = tikaResource .createParseContext ();
8789 Metadata metadata = Metadata .newInstance (context );
8890 try (TikaInputStream tis = tikaResource .setupMultipartConfig (attachments , metadata , context )) {
89- // No need to parse embedded docs for metadata-only extraction
90- context .set (DocumentSelector .class , metadata1 -> false );
91-
92- Parser parser = tikaResource .createParser ();
9391 TikaResource .logRequest (LOG , "/meta/config" , metadata );
94- tikaResource .parse (parser , LOG , info .getPath (), tis , new LanguageHandler () {
95- public void endDocument () {
96- metadata .set ("language" , getLanguage ().getLanguage ());
97- }
98- }, metadata , context );
99-
100- return Response .ok (metadata ).build ();
92+ return Response .ok (parseMetadata (tis , metadata , httpHeaders .getRequestHeaders (), context )).build ();
10193 }
10294 }
10395
@@ -107,19 +99,19 @@ public Response getMetadata(InputStream is, @Context HttpHeaders httpHeaders, @C
10799 ParseContext context = tikaResource .createParseContext ();
108100 Metadata metadata = Metadata .newInstance (context );
109101 try (TikaInputStream tis = TikaInputStream .get (is )) {
102+ tis .getPath (); // Spool to temp file for pipes-based parsing
110103 return Response
111- .ok (parseMetadata (tis , metadata , httpHeaders .getRequestHeaders (), info ))
104+ .ok (parseMetadata (tis , metadata , httpHeaders .getRequestHeaders (), context ))
112105 .build ();
113106 }
114107 }
115108
116109 /**
117- * Get a specific metadata field. If the input stream cannot be parsed, but a
118- * value was found for the given metadata field, then the value of the field
119- * is returned as part of a 200 OK response; otherwise a
120- * {@link javax.ws.rs.core.Response.Status#BAD_REQUEST} is generated. If the stream
121- * was successfully parsed but the specific metadata field was not found, then a
122- * {@link javax.ws.rs.core.Response.Status#NOT_FOUND} is returned.
110+ * Get a specific metadata field. If the document parses successfully but the
111+ * specific metadata field was not found, a
112+ * {@link javax.ws.rs.core.Response.Status#NOT_FOUND} is returned. Unlike the other
113+ * /meta endpoints, a bare field value has no envelope to embed a container-level
114+ * exception in, so that case is thrown (422) instead.
123115 * <p/>
124116 * Note that this method handles multivalue fields and returns possibly more
125117 * metadata value than requested.
@@ -131,35 +123,29 @@ public Response getMetadata(InputStream is, @Context HttpHeaders httpHeaders, @C
131123 * @param httpHeaders httpheaders
132124 * @param info info
133125 * @param field the tika metadata field name
134- * @return one of {@link javax.ws.rs.core.Response.Status#OK},
135- * {@link javax.ws.rs.core.Response.Status#NOT_FOUND}, or
136- * {@link javax.ws.rs.core.Response.Status#BAD_REQUEST}
126+ * @return one of {@link javax.ws.rs.core.Response.Status#OK} or
127+ * {@link javax.ws.rs.core.Response.Status#NOT_FOUND}
137128 * @throws Exception
138129 */
139130 @ PUT
140131 @ Path ("{field}" )
141132 @ Produces ({"text/csv" , "application/json" , "text/plain" })
142133 public Response getMetadataField (InputStream is , @ Context HttpHeaders httpHeaders , @ Context UriInfo info , @ PathParam ("field" ) String field ) throws Exception {
143-
144- // use BAD request to indicate that we may not have had enough data to
145- // process the request
146- Response .Status defaultErrorResponse = Response .Status .BAD_REQUEST ;
147134 ParseContext context = tikaResource .createParseContext ();
148- Metadata metadata = Metadata .newInstance (context );
149- boolean success = false ;
135+ Metadata metadata ;
150136 try (TikaInputStream tis = TikaInputStream .get (is )) {
151- parseMetadata ( tis , metadata , httpHeaders . getRequestHeaders (), info );
152- // once we've parsed the document successfully, we should use NOT_FOUND
153- // if we did not see the field
154- defaultErrorResponse = Response . Status . NOT_FOUND ;
155- success = true ;
156- } catch ( Exception e ) {
157- LOG . warn ( "Failed to process field {}" , field , e );
137+ tis . getPath (); // Spool to temp file for pipes-based parsing
138+ metadata = parseMetadata ( tis , Metadata . newInstance ( context ), httpHeaders . getRequestHeaders (), context );
139+ }
140+
141+ String containerException = metadata . get ( TikaCoreProperties . CONTAINER_EXCEPTION ) ;
142+ if ( containerException != null && ! containerException . isEmpty () ) {
143+ throw new TikaServerParseException ( new TikaException ( containerException ) );
158144 }
159145
160- if (success == false || metadata .get (field ) == null ) {
146+ if (metadata .get (field ) == null ) {
161147 return Response
162- .status (defaultErrorResponse )
148+ .status (Response . Status . NOT_FOUND )
163149 .entity ("Failed to get metadata field " + field )
164150 .build ();
165151 }
@@ -175,21 +161,26 @@ public Response getMetadataField(InputStream is, @Context HttpHeaders httpHeader
175161 .build ();
176162 }
177163
178- protected Metadata parseMetadata (TikaInputStream tis , Metadata metadata , MultivaluedMap <String , String > httpHeaders , UriInfo info )
179- throws IOException , TikaConfigException {
180- // Load default context from config (includes DigesterFactory from parse-context)
181- final ParseContext context = tikaResource .createParseContext ();
182- Parser parser = tikaResource .createParser ();
183- fillMetadata (parser , metadata , httpHeaders );
184- //no need to parse embedded docs
185- context .set (DocumentSelector .class , metadata1 -> false );
164+ /**
165+ * Parses via the shared pipes-backed PipesParser, stopping at the container document
166+ * (EmbeddedLimits maxDepth=0) with content capture off ("ignore" handler) -- metadata
167+ * only, matching /meta's contract. Set unconditionally so per-request config can't
168+ * turn content capture back on. A container-level exception is embedded in
169+ * CONTAINER_EXCEPTION here, not thrown; getMetadataField throws instead since it
170+ * returns a bare scalar with nowhere to embed it.
171+ */
172+ protected Metadata parseMetadata (TikaInputStream tis , Metadata metadata , MultivaluedMap <String , String > httpHeaders , ParseContext context )
173+ throws Exception {
174+ fillMetadata (null , metadata , httpHeaders );
175+ context .set (EmbeddedLimits .class , new EmbeddedLimits (0 , false , EmbeddedLimits .UNLIMITED , false ));
176+ context .set (ContentHandlerFactory .class ,
177+ new BasicContentHandlerFactory (BasicContentHandlerFactory .HANDLER_TYPE .IGNORE , -1 ));
186178
187179 TikaResource .logRequest (LOG , "/meta" , metadata );
188- tikaResource .parse (parser , LOG , info .getPath (), tis , new LanguageHandler () {
189- public void endDocument () {
190- metadata .set ("language" , getLanguage ().getLanguage ());
191- }
192- }, metadata , context );
193- return metadata ;
180+ List <Metadata > metadataList = tikaResource .parseWithPipes (tis , metadata , context , ParseMode .RMETA );
181+ if (metadataList .isEmpty ()) {
182+ return Metadata .newInstance (context );
183+ }
184+ return metadataList .get (0 );
194185 }
195186}
0 commit comments