elm / http

Make HTTP requests in Elm
https://package.elm-lang.org/packages/elm/http/latest
BSD 3-Clause "New" or "Revised" License
155 stars 46 forks source link

ArrayBuffer / Blob constructor conflict #56

Closed panthershark closed 5 years ago

panthershark commented 5 years ago

We have a situation where we fetch binary data with http, then prompt the user, then use Download.bytes to allow the user to save the file.

In IE11, using expectBytesResponse yields InvalidStateException b/c Blobs cannot be initialized from array buffers. This is because expectBytesResponse sets xhr.responseType = 'arraybuffer'.

Run this in IE11 to see the Blob constructor issue in isolation. new Blob( new ArrayBuffer([123]), { type: 'application/*' } );

We were able to solve the problem by creating a new expect factory function like this.

expectBlobResponse : (Result x a -> msg) -> (Http.Response Bytes -> Result x a) -> Http.Expect msg
expectBlobResponse toMsg toResult =
    Elm.Kernel.Http.expect "blob" identity (toResult >> toMsg)

We really don't want people to use Elm.Kernel inside of their application code so I'm gonna submit a PR to add this to the library.

Please let me know what you think. :)

evancz commented 5 years ago

There is no "blob" concept in Elm, so I would rather not expose a function like this in Elm itself.

Is there any way to detect if it is an IE browser and do this trick only in that situation?

E.g. If https://github.com/elm/file/pull/7 fixes https://github.com/elm/file/issues/5 as well, why is this preferable to that?

panthershark commented 5 years ago

yeah.. the naming is kinda tricky, but I'll try to clear up what is happening. It is a cross-cutting concern of elm/http and elm/file.

The underlying js thing that happened expectBytes sets xhr.responseType = 'arraybuffer' which is what causes the problem when trying to stream the bytes using Download.bytes. In turn, IE doesn't like new Blob(arraybuffer) from here - https://github.com/elm/file/blob/master/src/Elm/Kernel/File.js#L49

To summarize,

  1. browser runtime generates arraybuffer from the xhr internals
  2. elm/file or elm/bytes copies it around in kernel code
  3. Download.bytes attempts to convert it using new Blob() which makes an IE InvalidStateError

This might be a decent approach, but BlobBuilder is a deprecated api interface. I'm not sure how much y'all care about that - https://github.com/elm/file/pull/7

For context, this is not a serious issue for our app. The OG bug report for this was https://github.com/elm/file/issues/5

The application scenario was: A user needs to be prompted when downloading a file. The app was downloading the bytes and holding them in memory until the user responds to the prompt.

Our code was changed to do this Our app changed the implementation to simply initiate the download after the prompt.


I was helping out with troubleshooting the original bug report on our end. I do not have a strong feeling about whether this code should be accepted. I did think it was worth a conversation.

panthershark commented 5 years ago

Closing this issue at Evan's request as the SSCCE is here. https://github.com/elm/http/issues/58

evancz commented 5 years ago

I think it makes sense to use https://github.com/elm/http/issues/58 as the canonical statement of this problem. Thanks again for creating that!