-
Notifications
You must be signed in to change notification settings - Fork 4
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
fs2-data-xml streaming parser #25
Changes from 1 commit
1ca64f2
2e2935b
32e569e
f92af16
62bfde3
d2426eb
72b7b60
96e38de
be9d87f
208fd19
ceb7dcd
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -18,19 +18,19 @@ package org.http4s | |
package scalaxml | ||
|
||
import cats.effect.Concurrent | ||
import cats.syntax.all._ | ||
import fs2.data.xml.XmlException | ||
import fs2.data.xml.scalaXml._ | ||
import org.http4s.Charset.`UTF-8` | ||
import org.http4s.headers.`Content-Type` | ||
|
||
import java.io.ByteArrayInputStream | ||
import java.io.StringWriter | ||
import javax.xml.parsers.SAXParserFactory | ||
import scala.util.control.NonFatal | ||
import scala.xml.Elem | ||
import scala.xml.InputSource | ||
import scala.xml.SAXParseException | ||
import scala.xml.XML | ||
|
||
trait ElemInstances { | ||
@deprecated("0.23.12", "This factory is no longer used") | ||
protected def saxFactory: SAXParserFactory | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is the (semantically) breaking change. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Replacing SAX will also change the types of errors that are raised. |
||
|
||
implicit def xmlEncoder[F[_]](implicit charset: Charset = `UTF-8`): EntityEncoder[F, Elem] = | ||
|
@@ -52,18 +52,23 @@ trait ElemInstances { | |
implicit def xml[F[_]](implicit F: Concurrent[F]): EntityDecoder[F, Elem] = { | ||
import EntityDecoder._ | ||
decodeBy(MediaType.text.xml, MediaType.text.html, MediaType.application.xml) { msg => | ||
val source = new InputSource() | ||
msg.charset.foreach(cs => source.setEncoding(cs.nioCharset.name)) | ||
|
||
collectBinary(msg).flatMap[DecodeFailure, Elem] { chunk => | ||
source.setByteStream(new ByteArrayInputStream(chunk.toArray)) | ||
val saxParser = saxFactory.newSAXParser() | ||
try DecodeResult.successT[F, Elem](XML.loadXML(source, saxParser)) | ||
catch { | ||
case e: SAXParseException => | ||
DecodeResult.failureT(MalformedMessageBodyFailure("Invalid XML", Some(e))) | ||
case NonFatal(e) => DecodeResult(F.raiseError[Either[DecodeFailure, Elem]](e)) | ||
} | ||
DecodeResult { | ||
msg.bodyText | ||
.through(fs2.data.xml.events()) | ||
.through(fs2.data.xml.dom.documents) | ||
.head | ||
.compile | ||
.lastOrError | ||
.map { | ||
_.docElem match { | ||
case e: Elem => Right(e) | ||
case _ => Left(MalformedMessageBodyFailure("Invalid XML")) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Instead of this charade, maybe this should become an |
||
} | ||
} | ||
.recover { case ex: XmlException => | ||
Left(MalformedMessageBodyFailure("Invalid XML", Some(ex))) | ||
} | ||
.widen | ||
} | ||
} | ||
} | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I couldn't decide whether or not to bump the base version. We can make this change binary-compatibly, it's more about semantics.