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

Don't attach upload handler if they do not exist on the originating request #304

Merged
merged 1 commit into from
May 19, 2020

Conversation

ryanto
Copy link
Contributor

@ryanto ryanto commented May 18, 2020

A small change that needs a lot of explanation :)

Most often when you are using CORS the browser will send a preflight request to the remote server to verify that CORS is allowed. However, there are "simple" requests that do not need a preflight check. See: https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS

You can think of these as requests that the browser would normally be allowed to send in a world where XMLHttpRequest didn't exist.

One of the rules for a request being simple is...

No event listeners are registered on any XMLHttpRequestUpload object used in the request; these are accessed using the XMLHttpRequest.upload property.

This causes an issue with pretender because we add an onprogress function to the passthrough request's upload property. This means that any simple request that is copied to a pass though request will lose its "simple" status. This is breaking behavior, because requests that didn't need to preflight will now start preflighting if there is a pretender server running.

This will cause problems if the remote server is not expecting a preflight request. To show this, I made a little example server and client app that uses simple requests that are allowed to CORS. However, the server does not support preflighting.

Here's the server.

let express = require('express')
let fs = require('fs')
let path = require('path')


let api = express();

api.post("/testing", (req, res) => {
  console.log('server got a post request')
  res.set('Access-Control-Allow-Origin', 'http://localhost:3002')
  res.send("It worked!")
});

api.options("/testing", (req, res) => {
  console.log('server got an options request')
  res.status(404).send("This server does not support option requests.")
})

api.listen(3001)


let content = express()

content.get("/", (req, res) => {
  res.set('Content-Type', 'text/html')
  res.send(fs.readFileSync(path.join(__dirname, "index.html")))
})

content.listen(3002)

console.log("visit http://localhost:3002")

And here's the client.

<script type="text/javascript" src="https://unpkg.com/route-recognizer@0.3.4/dist/route-recognizer.js"></script>
<script type="text/javascript" src="https://unpkg.com/fake-xml-http-request@2.1.1/fake_xml_http_request.js"></script>
<script type="text/javascript" src="https://unpkg.com/pretender@3.4.1/dist/pretender.js"></script>

<script>
  window.runRequest = () => {
    let request = new XMLHttpRequest();
    request.open('POST', 'http://localhost:3001/testing');
    request.setRequestHeader(
      'Content-Type',
      'application/x-www-form-urlencoded'
    );
    request.onreadystatechange = (...args) => {
      console.log('state change', ...args);
    };
    request.send("a=123&b=456")
  }
</script>

<button onclick="javascript:runRequest()">Send request</button>

<script>
  window.turnOnPretender = () => {
    window.pretender = window.pretender ?
      window.pretender :
      new Pretender(function() {
        this.post('http://localhost:3001/testing', this.passthrough);
      })
  }

  window.turnOffPretender = () => {
    window.pretender && window.pretender.shutdown()
    window.pretender = null
  }
</script>


<button onclick="javascript:turnOnPretender()">Turn on pretender</button>
<button onclick="javascript:turnOffPretender()">Turn off pretender</button>

If you visit the client app and open your dev console, you'll see the request works fine and there are no errors. However, if you turn on pretender you'll see that the request is now blocked by CORS. If you're using chrome, you should display options requests to better see this.

The fix for this is to only modify the pass through request's upload property only if the function exists on the originating requests upload property.

@xg-wang xg-wang added the bug label May 19, 2020
@xg-wang xg-wang merged commit f2142bc into pretenderjs:master May 19, 2020
@xg-wang
Copy link
Member

xg-wang commented May 19, 2020

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

Successfully merging this pull request may close these issues.

2 participants