Swagger-ui: File download via content-disposition header corrupts file

Created on 16 Sep 2015  Â·  104Comments  Â·  Source: swagger-api/swagger-ui

lnowak (https://github.com/swagger-api/swagger-ui/pull/1238) noted an issue where a file download triggered via the Content-Disposition header will result in a link to download the file, but the file will be corrupt. I am also seeing this issue in my environment.

The response headers:
{
"Cache-Control": "no-cache, no-store",
"Content-Disposition": "attachment; filename=\"example.zip\"",
"Transfer-Encoding": "chunked",
"Content-Type": "application/octet-stream"
}

This is the download URL that it displays in the UI. If I download via this link, I get a corrupt file. If I use the link directly from the browser, I get a valid download.
blob:http%3A//localhost%3A8090/9222e8a1-8628-476f-9341-372d68729d58

Most helpful comment

I don't know if this will be helpful, but I have created a test service here

http://testswaggerpostdownload.azurewebsites.net/swagger/ui/index#/Echo

This just echos back the uploaded file as the result of the POST request, allowing you to specify the response content-type too (defaulting to application/octet-stream).

This site is running Swashbuckle 5.4.0 - which is a .NET package for including swagger in a web project. Swashbuckle 5.4.0 seems to be using swagger-ui 2.2.0 (https://github.com/domaindrivendev/Swashbuckle/tree/v5.4.0).

The error for me is that if you pick any binary format file to test with then the file is corrupted after downloading the response body using swagger-ui.

I realise that swagger-ui 2.2.0 is out of date, but if I use newer versions of Swashbuckle which use swagger-ui 2.2.4 I get this error in the browser when pressing the 'try it out' button.

swagger-ui-min-js:14 Uncaught TypeError: Failed to execute 'createObjectURL' on 'URL': No function was found that matched the signature provided.
    at showStatus (swagger-ui-min-js:14)
    at showCompleteStatus (swagger-ui-min-js:14)
    at response (swagger-ui-min-js:9)
    at p (swagger-ui-min-js:7)
    at Object.t.on.response (swagger-ui-min-js:7)
    at Object.e.complete (swagger-ui-min-js:7)
    at k (jquery-1-8-0-min-js:2)
    at Object.fireWith (jquery-1-8-0-min-js:2)
    at y (jquery-1-8-0-min-js:2)
    at XMLHttpRequest.d (jquery-1-8-0-min-js:2)

I hope that this is helpful.

All 104 comments

+1

+1

Similar, but not the same here: I get the same corrupt file if I use the link directly via browser. So I guess the data is already corrupted when retrieving the response.

+1

+1
If i try to download file via browser then it works, but with swagger download link, it gives me currupt file.

@lmprice you found any work arround this??

+1

+1

+1

+1

+1

+1

@fehguy @mohsen1

I got first to https://github.com/swagger-api/swagger-ui/issues/374 before stumbling upon this.

The problem is that there is (AFAIK) no support for XHR responseType='arraybuffer'.
The other (potential) problem is that the served file download content is actually being trimmed.

Swagger-ui uses swagger-js, which in turn by default uses superagent, but swagger-js never tells superagent to use responseType = 'arraybuffer'.
Swagger-js already have an issue for this: https://github.com/swagger-api/swagger-js/issues/123

@vivex @lmprice I don't think this is possible to work around without changing the original swagger code.

+1

+1

+1

+1

+1

+1

Please give https://github.com/swagger-api/swagger-ui/pull/2404 a shot and post back. I'll merge after feedback

Is this already fixed?
For me it still corrupts file and doubles its size.

Yes, that's why the issue was closed. Please open a new issue if you think it's not fixed, and share some details.

Also corrupt file here.

On Sunday, 23 October 2016, gkozyryatskyy [email protected] wrote:

Is this already fixed?
For me it still corrupts file and doubles its size.

—
You are receiving this because you commented.
Reply to this email directly, view it on GitHub
https://github.com/swagger-api/swagger-ui/issues/1605#issuecomment-255597455,
or mute the thread
https://github.com/notifications/unsubscribe-auth/AAEhW-g04LcIXpsveJnzcjhgYWYBcTAvks5q24hYgaJpZM4F-d_0
.

Still same issue, double the size and corrupt the file

Hmm

The same for me. Example in HEX,
Response body:
AE CE 1C E9 6F
After download file, file contains:
EF BF BD EF BF BD 1C EF BF BD 6F

This piece of code:
var binaryData = []; binaryData.push(content); href = window.URL.createObjectURL(new Blob(binaryData, {type: type}));

works incorrectly and I can reproduce it in simple solution.

Data point:

Using 2.2.6 I get correct behaviour for a GET request that returns a binary attachment, but corruption for a POST request that returns the same binary attachment.

I'm using 2.2.6 and have a problem with GET requests as well

+1

+1

That's a lot of +1's! Sorry this took so long, but it will be addressed by #2427

For me, it doesn't seem to be fixed.

Code in https://github.com/swagger-api/swagger-ui/blob/v2.2.8/src/main/javascript/view/OperationView.js
lines 707-709 still brakes the attached files:

var binaryData = [];
binaryData.push(content);
href = window.URL.createObjectURL(new Blob(binaryData, {type: type}));

My response header:

{
  "date": "Mon, 28 Nov 2016 15:41:09 GMT",
  "server": "Microsoft-IIS/10.0",
  "x-aspnet-version": "4.0.30319",
  "x-powered-by": "ASP.NET",
  "content-type": "image/png",
  "status": "200",
  "cache-control": "private",
  "content-disposition": "attachment; filename=boty1px.png"
}

Even if I change code to:

var arrayBuffer = new ArrayBuffer(content.length);
var uint8Array = new Uint8Array(arrayBuffer);
for (var i = 0; i < content.length; i++) {
uint8Array[i] = content.charCodeAt(i);
}
href = window.URL.createObjectURL(new Blob([uint8Array], {type: type}));

file is still broken, usually the difference in one byte (checked on small files)

Please share your request headers. I'm guessing you are not asking for a binary file type?

Still having problems with 2.2.8:

Response headers

Connection:keep-alive
Content-Disposition:attachment; filename=File.zip
Content-Length:1116714
Content-Type:application/zip
Date:Mon, 28 Nov 2016 22:13:50 GMT
Server:nginx/1.6.2
X-Powered-By:Sails 

The downloaded file has a size of 2 MB, while downloading the file with curl results in a (valid) file with a size for 1,2 MB

Request headers

GET /downloadFile HTTP/1.1
Host: my.server.com
Connection: keep-alive
Accept: application/zip
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.98 Safari/537.36
Authorization: JWT (removed token)
Referer: https://my.server.com/swagger-ui/?url=https://my.server.com/link/to/swagger.yaml
Accept-Encoding: gzip, deflate, sdch, br
Accept-Language: de-DE,de;q=0.8,en-US;q=0.6,en;q=0.4

Looks like the check to see if the file is binary (which uses blob) doesn't include zip:

SuperagentHttpClient.prototype. binaryRequest = function (accept) {
  if(!accept) {
    return false;
  }
  return (/^image/i).test(accept)
    || (/^application\/pdf/).test(accept)
    || (/^application\/octet-stream/).test(accept);
};

Can you please try with a raw PDF or image? And open an issue in swagger-js about the application/zip?

I've fixed it by replacing application/zip with application/octet-stream

@fehguy Do you think there might be a better way to detect a binary file? There's a wide variety of mime types that are binary (including user-defined types) so I don't think a list like this will work.

Maybe it should be possible to configure the types to treat as binary?

Yea, this technique isn't great. I believe the issue is that when we use binary, we lose the ability to read some response headers via xhr. Thus the binary is more "opt-in" than "opt-out". If anyone has a better technique, I'm all for it.

@fehguy
If you are asking for accept parameter, then yes it is application/json:

:authority:api.sss.com
:method:GET
:path:/rest/v1/zmeigor4/projects/0/documents/35073755?alt=media
:scheme:https
accept:application/json
accept-encoding:gzip, deflate, sdch, br
accept-language:en-GB,en-US;q=0.8,en;q=0.6,ru;q=0.4,uk;q=0.2
authorization:Bearer 6drhAdDWblbablalbal

My endpoint can return json object or file of any time depending on input parameter.

+1

+1

+1

Please try with 3.0. Keeping the ticket open for feedback.

I am using the latest swagger UI . i am not getting the response body for content-type like application/pdf and application/csv .
The response has 200 status and also response body in browser network section contains raw data

My response headers contains :
Access-Control-Allow-Credentials:true
Access-Control-Allow-Methods:GET, POST, OPTIONS
Access-Control-Allow-Origin:http://localhost:3000
Connection:keep-alive
Content-Disposition:attachment; filename="Rakesh_www.webdemo.com_TEST_1495417604_2016-09-21_.csv"
Content-Encoding:gzip
Content-Type:application/octet-stream
Date:Wed, 29 Mar 2017 10:38:54 GMT
Server:nginx/1.4.6 (Ubuntu)
Set-Cookie:csessionid=373d14ff968ad6e57163e01d6915db4323932; Path=/; HttpOnly
Transfer-Encoding:chunked
X-FRAME-OPTIONS:SAMEORIGIN

@rockeshub have you tried returning the correct content-type for the CSV or PDF instead of using application/octet-stream?

@buunguyen i haven't tried with other content-type, but if i call the same API using postman its working fine i am able to download the file. Also according to response-body.jsx i should get " Unknown response type" if my type is not proper.

For 2.2.10 file download works fine for GET queries. If I'm doing a POST query with FORM parameter type=file and trying to download file in Response (Produces: application/octet-stream, Responses.Schema.Type=file) the result file still corrupts. If I remove parameter with type=file from POST query, all works fine.
For 3.x file download doesn't work at all.

@precizeman do you have a public API to share to see the file download issue?

I will send link in next week (Monday-Tuesday), at this time I’m developing app.

From: Ron [mailto:[email protected]]
Sent: Tuesday, May 9, 2017 12:42 AM
To: swagger-api/swagger-ui swagger-ui@noreply.github.com
Cc: Mikhail Andreev andreyevmb@live.ru; Mention mention@noreply.github.com
Subject: Re: [swagger-api/swagger-ui] File download via content-disposition header corrupts file (#1605)

@precizemanhttps://github.com/precizeman do you have a public API to share to see the file download issue?

—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHubhttps://github.com/swagger-api/swagger-ui/issues/1605#issuecomment-299969716, or mute the threadhttps://github.com/notifications/unsubscribe-auth/AYhggd2oS5CYDHkxK3ugPWX3aLF76kVIks5r33AUgaJpZM4F-d_0.

+1

+1

+1

+1

For everyone who +1'ed, it would be great to get live examples for us to see the issue in action. That would be a great step to get it fixed.

I don't know if this will be helpful, but I have created a test service here

http://testswaggerpostdownload.azurewebsites.net/swagger/ui/index#/Echo

This just echos back the uploaded file as the result of the POST request, allowing you to specify the response content-type too (defaulting to application/octet-stream).

This site is running Swashbuckle 5.4.0 - which is a .NET package for including swagger in a web project. Swashbuckle 5.4.0 seems to be using swagger-ui 2.2.0 (https://github.com/domaindrivendev/Swashbuckle/tree/v5.4.0).

The error for me is that if you pick any binary format file to test with then the file is corrupted after downloading the response body using swagger-ui.

I realise that swagger-ui 2.2.0 is out of date, but if I use newer versions of Swashbuckle which use swagger-ui 2.2.4 I get this error in the browser when pressing the 'try it out' button.

swagger-ui-min-js:14 Uncaught TypeError: Failed to execute 'createObjectURL' on 'URL': No function was found that matched the signature provided.
    at showStatus (swagger-ui-min-js:14)
    at showCompleteStatus (swagger-ui-min-js:14)
    at response (swagger-ui-min-js:9)
    at p (swagger-ui-min-js:7)
    at Object.t.on.response (swagger-ui-min-js:7)
    at Object.e.complete (swagger-ui-min-js:7)
    at k (jquery-1-8-0-min-js:2)
    at Object.fireWith (jquery-1-8-0-min-js:2)
    at y (jquery-1-8-0-min-js:2)
    at XMLHttpRequest.d (jquery-1-8-0-min-js:2)

I hope that this is helpful.

I also get a '-' character at the start and end of my file name, as well as the file being bloated and corrupted. Even the test service @rwg0 provided does the same.

+1 also having issue with corrupt file and hyphens on start and end of file name.

+1 also having issue with corrupt file

+1

+1 binary file being doubled and corrupted. Using Swashbuckle.AspNetCore 1.0.0.

Just spent 2 days searching why my downloads where corrupted.
+1

+1

I suspect it's a UTF-8 vs ANSI problem.

@thestonehead Good call. I'll test out setting different charset parameters in the header to see if one particular charset resolves this.

+1 binary file being ~doubled and corrupted

+1

I have the same issue with pdf files

+1

Folks who are adding +1s: what version of Swagger-UI are you experiencing this with?

+1
2.7.0
zip file doubled and corrupted.

How can I check the version ? My swagger interface is generated by flask-restplus plugin

v2.2.0
pdf files are doubled and corrupted

Hi everyone - for everyone's convenience we just added a documentation file to help you detect which version of Swagger-UI you're using. You can find it here.

Please note that unless you depend on swagger-ui directly as a stand alone package from npm (the one that's supplied from us), you are getting swagger-ui packaged by different providers (especially in other languages like java, php, python and so on) - and they don't always follow our versioning scheme. For example - there's no swagger-ui 2.7.0.

Remember, we need the version to be able to analyze the problems better, and without accurate information, we won't be able to assist.

@webron - thanks for that - v2.2.10 here - this is what is bundled with ServiceStack at the moment.

@webron I guess "2.7.0" is the latest version of Springfox, which embeds Swagger UI 2.2.10.
Here is what I've experienced on my side:

  • If "produces": ["/"], the file downloaded is corrupted and the file size is ~doubled. Using "produces": ["application/octet-stream"] fixes the issue
  • hyphens are prepended/appended to the file name, when a Content-Disposition header is provided

swagger UI version v2.2.6 from flask-Restplus
pdf file corrupted

I have the same problem with Swagger v2.2.6 on flask-Restplus. I was able to solve it partially with the following trick:
https://stackoverflow.com/questions/26971491/how-do-i-link-to-images-not-in-static-folder-in-flask

In post request return link to the file and retrieve it with get.

Thanks everyone who provided their versions. It is unlikely that we'll issue any fixes to the 2.X branch of the code due to technical reasons.

While I understand a lot of you use the UI as provided as part of the libraries, at least for testing purposes, you should be able to test the latest version easily, even without installing it as part of your app, just running it locally. Can you give it a try and report back?

@webron Unfortunately, the latest version doesn't support file download yet #3149

@eryi - The latest version seems to be working fine, I do get a download link:
http://swashbuckletest.azurewebsites.net/swagger/ui/index#/Image/Image_Put

I think this issue can be closed

Which version are you using?

On Nov 12, 2017 07:41, "Helder Sepulveda" notifications@github.com wrote:

@eryi https://github.com/eryi - The latest version seems to be working
fine, I do get a download link:
http://swashbuckletest.azurewebsites.net/swagger/ui/index#/Image/Image_Put

I think this issue can be closed

—
You are receiving this because you commented.
Reply to this email directly, view it on GitHub
https://github.com/swagger-api/swagger-ui/issues/1605#issuecomment-343738093,
or mute the thread
https://github.com/notifications/unsubscribe-auth/AcYP9E0H_H5MbFiFQCX1mwiVxypGV3kIks5s1vWDgaJpZM4F-d_0
.

@pg26 I'm always using the latest, as of this note:

{"swaggerUi":
  {
  "version":"3.4.4",
  "gitRevision":"gfadc522f",
  "gitDirty":true,
  "buildTimestamp":"Sat, 11 Nov 2017 07:20:24 GMT",
  "machine":"banjo"
  }
}

Here are instructions to check the version:
https://github.com/swagger-api/swagger-ui/blob/master/docs/version-detection.md

+1 swagger 1.1.0 for aspnetcore returns corrupted double-sized files

@SeletskySergey what is:

swagger 1.1.0 for aspnetcore

perhaps you mean Swashbuckle.AspNetCore?
Check the version of swagger-ui see if they are using the latest

+1

@HerrDerb Sorry to hear, can you provide some more details?
What version of the UI are you using?

I'm currently on

    <dependency>
        <groupId>io.springfox</groupId>
        <artifactId>springfox-swagger2</artifactId>
        <version>2.7.0</version>
    </dependency>
    <dependency>
        <groupId>io.springfox</groupId>
        <artifactId>springfox-swagger-ui</artifactId>
        <version>2.7.0</version>
    </dependency>

@HerrDerb that version number is very strange ...
Last on record for the 2.x branch was: v2.2.10

Compare yours with the PetStore sample, see if yours looks anything like that, the sample is using the latest (3.x) and it is quite different from the previous major version.

I think you should contact springfox see if they can point you on the right direction.

As @webron mentioned upthread:

Thanks everyone who provided their versions. It is unlikely that we'll issue any fixes to the 2.X branch of the code due to technical reasons.

While I understand a lot of you use the UI as provided as part of the libraries, at least for testing purposes, you should be able to test the latest version easily, even without installing it as part of your app, just running it locally. Can you give it a try and report back?

3149 is closed now, so you all should be able to test 3.x 😄

+1 binary file being doubled and corrupted. Using Swashbuckle.AspNetCore 1.2.0.

2018-03-05 - issue now resolved by upgrading to Swashbuckle.AspNetCore Version=2.2.0

+1. Corrupts xlxs files. Using django-rest-swagger 2.1.2.

@estianross Can you provide a link to your API?

Unfortunately not as this is still in testing currently. Testing through drf browsable api and curl does not corrupt the file though, only by hitting the endpoint through swagger does it get corrupted.

@estianross What can you share that would help us troubleshoot?

Only a description of the issue in hopes and steps you can take to hopefully replicate it.
Firstly post to a view derived from drf's GenericAPIView
Second generate a workbook using openpyxl (wb = openpyxl.Workbook())
Next populate with a single example row (wb.active.append(row))
Finally:

filename = 'test.xlsx'
response = HttpResponse(content_type='application/vnd.ms-excel;charset=UTF-8', content=save_virtual_workbook(wb))
response['Content-Disposition'] = 'attachment; filename=%s' % filename
return response

Hopefully that's something to help, like I said above it's not a critical issue for me as it only shows up while testing through swagger, not while using the endpoint directly

@estianross If your Swagger-UI looks like what they have on the image here:
https://marcgibbons.com/django-rest-swagger/#quick-start

They are using an old version (2.x), that version is no longer supported and has not receive any attention in while, see if you can get them to upgrade to the latest.

Thanks for the assistance :D will do

On 27 Feb 2018 16:01, "Helder Sepulveda" notifications@github.com wrote:

@estianross https://github.com/estianross If your Swagger-UI looks like
what they have on the image here:
https://marcgibbons.com/django-rest-swagger/#quick-start

They are using an old version (2.x), that version is no longer supported
and has not receive any attention in while, see if you can get them to
upgrade to the latest.

—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
https://github.com/swagger-api/swagger-ui/issues/1605#issuecomment-368887295,
or mute the thread
https://github.com/notifications/unsubscribe-auth/AaeYjIMlG7aEPf-nkfEEXLT7N4bnu_qxks5tZArFgaJpZM4F-d_0
.

@estianross looking at the activity of the project:
https://github.com/marcgibbons/django-rest-swagger/pulse/monthly

There hasn’t been any commit activity on marcgibbons/django-rest-swagger in the last month.

That is not a good sign ... See if there are any alternatives out there

@SeletskySergey
You need to update version of Swashbuckle.AspNetCore.SwaggerUI to 2.1.0 . No need to change any other version. it will work fine

Can anyone confirm that this is still an issue with the latest 3.x version?

I can confirm that with

<groupId>io.springfox</groupId>
<artifactId>springfox-swagger-ui</artifactId>
<version>2.8.0</version>

the problem is solved. I don't have an 3.x.x. around.

@HerrDerb, thanks for the info!


I'm going to close this out - we've been courting reports for this being a problem in 3.x since last August, and haven't gotten any.

As a reminder, Swagger-UI 2.x is no longer under development, so we won't be addressing problems with any versions before 3.0.0.

Thanks to everyone for providing information!

@SeletskySergey How do we update the Swashbuckle.AspNetCore.SwaggerUI in Django Rest Swagger?

If you still using Swashbuckle and swagger.ui 2.2.10 like me. This workaround worked for me;

`
(function () {
var currentXhr;
var currentXhrFn;
var currentXhrArgs;

    var origOpen = XMLHttpRequest.prototype.open;
    XMLHttpRequest.prototype.open = function () {

      var bypass = false;

      for (var i = 0; i < arguments.length; i++) {
        if (arguments[i] === "bpfpdf") {
          bypass = true;
          break;
        }
      }

      if (!bypass) {
        currentXhr = this;
        currentXhrFn = this.onreadystatechange;
        currentXhrArgs = arguments;

        this.onreadystatechange = function () { }

        this.addEventListener('load', function () {
          if (this.getAllResponseHeaders().indexOf("content-type: application/pdf") > -1) {
            var newRequest = new XMLHttpRequest();
            newRequest.responseType = "arraybuffer";

            newRequest.addEventListener("readystatechange", function () {
              if (this.readyState === 4) {
                Object.defineProperty(currentXhr, "response", { writable: true });
                Object.defineProperty(currentXhr, "responseText", { writable: true });

                currentXhr.response = this.response;
                currentXhr.responseText = null;

                currentXhrFn.apply(newRequest);
              }
            });

            newRequest.open(currentXhrArgs[0], currentXhrArgs[1], currentXhrArgs[2], "bpfpdf");

            newRequest.setRequestHeader("Authorization",
              "Basic " +
              btoa(swaggerUi.api.clientAuthorizations.authz.basicAuth.username + ":" + swaggerUi.api.clientAuthorizations.authz.basicAuth.password));

            newRequest.send(null);

          } else {
            if (currentXhrFn != null) {
              currentXhrFn.apply(this);
            }
          }
        });
      }

      var params = Array.prototype.slice.call(arguments);

      if (bypass) {
        params.pop();
      }

      origOpen.apply(this, params);
    };
  })();

`

Was this page helpful?
0 / 5 - 0 ratings

Related issues

LaysDragon picture LaysDragon  Â·  3Comments

liuya05 picture liuya05  Â·  3Comments

songtianyi picture songtianyi  Â·  3Comments

Deraen picture Deraen  Â·  4Comments

prabhat1790 picture prabhat1790  Â·  3Comments