Skip to content
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

Accept headers can corrupt binary downloads #992

Open
sashadt opened this issue Apr 21, 2016 · 1 comment
Open

Accept headers can corrupt binary downloads #992

sashadt opened this issue Apr 21, 2016 · 1 comment

Comments

@sashadt
Copy link

sashadt commented Apr 21, 2016

Accept: text/html,*/* headers in request cause binary file (zip) downloads to be corrupted. Content type of response content-type: "application/octet-stream" is not being used to process the response correctly. These headers are automatically being set by Chrome. If I instead test the same request with curl ... -H 'Accept: */*' alternatively, I am able to download the same zip via the proxy without corrupting it.

Here is the sequence of events:

[Browser] (Accept: "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8") -->
[Gulp Server] --> 
[node-http-proxy] --> 
[Web Server] (content-type: "application/octet-stream") --> 
[node-http-proxy] --> 
[Gulp Server] --> 
[Browser]

Resulting downloads are larger than original files on the server. And unzip -t indicates it is a corrupted archive. In fact, using cat a.zip | iconv -f utf-8 -t utf-8 > /dev/null test on the corrupted file reveals they are in a valid UTF-8 format. This suggests that proxy may not be honoring the content-type response coming back from the web server. Instead it may be using "text/html" as the content type to process files being downloaded.

Attempting to rewrite the Accept headers to */* using following method also fails.

proxy.on('proxyReq', function(proxyReq, req, res, options) {
  proxyReq.setHeader('Accept', '*/*');
  req.headers.accept = '*/*';
});

Here is the code used to proxy the requests:

var httpProxy = require('http-proxy');
var express = require('express');
var livereload = require('connect-livereload');
var http = require('http');

var proxy = httpProxy.createProxyServer({
  target: {
    host: settings.gateway.host,
    port: settings.gateway.port
  }
});

function gatewayMiddleware(req, res, next) {
  if (req.originalUrl.indexOf('/ws/') === 0 || req.originalUrl.indexOf('/proxy/') === 0) {
    console.log(req.method + ' ' + req.originalUrl);
    proxy.proxyRequest(req, res);
  } else {
    next();
  }
}

  var app = express();
  app.use(function(req, res, next) {
    res.header('Access-Control-Allow-Origin', '*');
    res.header('Access-Control-Allow-Headers', '*');
    next();
  });
  app.use(livereload({ port: 35729 }));
  app.use(gatewayMiddleware);

  var server = http.createServer(app);

  server.on('upgrade', function (req, socket, head) {
    proxy.ws(req, socket, head);
  });

  server.listen(9000)

...
@sashadt
Copy link
Author

sashadt commented Apr 21, 2016

For now I found a workaround of setting download attribute on the download links.

<a href="...." download>...</a>

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant