| 64 | } |
| 65 | |
| 66 | @Override |
| 67 | public Object decode(Response response, Type type) throws IOException { |
| 68 | if (response.status() == 404 || response.status() == 204) return Util.emptyValueOf(type); |
| 69 | if (response.body() == null) return null; |
| 70 | while (type instanceof ParameterizedType) { |
| 71 | ParameterizedType ptype = (ParameterizedType) type; |
| 72 | type = ptype.getRawType(); |
| 73 | } |
| 74 | if (!(type instanceof Class)) { |
| 75 | throw new UnsupportedOperationException( |
| 76 | "JAXB only supports decoding raw types. Found " + type); |
| 77 | } |
| 78 | |
| 79 | try { |
| 80 | SAXParserFactory saxParserFactory = SAXParserFactory.newInstance(); |
| 81 | /* Explicitly control sax configuration to prevent XXE attacks */ |
| 82 | saxParserFactory.setFeature("http://xml.org/sax/features/external-general-entities", false); |
| 83 | saxParserFactory.setFeature("http://xml.org/sax/features/external-parameter-entities", false); |
| 84 | saxParserFactory.setFeature("http://apache.org/xml/features/disallow-doctype-decl", false); |
| 85 | saxParserFactory.setFeature( |
| 86 | "http://apache.org/xml/features/nonvalidating/load-external-dtd", false); |
| 87 | saxParserFactory.setNamespaceAware(namespaceAware); |
| 88 | |
| 89 | return jaxbContextFactory |
| 90 | .createUnmarshaller((Class<?>) type) |
| 91 | .unmarshal( |
| 92 | new SAXSource( |
| 93 | saxParserFactory.newSAXParser().getXMLReader(), |
| 94 | new InputSource(response.body().asInputStream()))); |
| 95 | } catch (JAXBException | ParserConfigurationException | SAXException e) { |
| 96 | throw new DecodeException(response.status(), e.toString(), response.request(), e); |
| 97 | } finally { |
| 98 | if (response.body() != null) { |
| 99 | response.body().close(); |
| 100 | } |
| 101 | } |
| 102 | } |
| 103 | |
| 104 | public static class Builder { |
| 105 | private boolean namespaceAware = true; |