提交 1e4a6151 编写于 作者: E Emily Eisenberg

Make fetch add a `Content-Type` header based on the type of the body.

Summary: The process of extracting a body from a passed in body object
(described here: https://fetch.spec.whatwg.org/#concept-bodyinit-extract)
creates both a byte stream and a corresponding `Content-Type` value. These two
values are used in the constructor of `Request` and `Response` objects to
initialize the body and to set an initial `Content-Type` header.

This change makes `Body._initBody()` return the `Content-Type` value
corresponding to the type of the object passed in, and to set that header in
the corresponding `Request` and `Response` objects that are being constructed.

There's a little bit of a dance I need to do in Request to keep track of where
the body is coming from, because we're only supposed to be setting the
`Content-Type` header if we're getting the body from the options passed in, not
if we're copying it from another `Request`. See step 32 of
https://fetch.spec.whatwg.org/#dom-request. (This was caught by one of the
tests. Yay tests!)

I added some corresponding tests to make sure this works.

Test Plan:
I'm a little bit confused about how to run the tests normally, but this is what
I did:

 - Run `make lint`, see that everything passes
 - Start up the test server by running `node script/server 3900 &`
 - Visit http://localhost:3900/test/test.html and
   http://localhost:3900/test/test-worker.html in Chrome and see that all of
   the tests pass.

From what I can tell, running the tests in Chrome just used the native fetch
objects, so to test the polyfill I added `window.fetch = null` in
test/test.html before it includes '../fetch.js', and added `self.fetch = null`
in test/worker.js before it imports '../fetch.js'. Then:

 - Visit http://localhost:3900/test/test.html and
   http://localhost:3900/test/test-worker.html in Chrome and see that all of
   the tests pass.

Reviewers: @jeresig
上级 133bd732
......@@ -128,10 +128,16 @@
this._bodyInit = body
if (typeof body === 'string') {
this._bodyText = body
return 'text/plain;charset=UTF-8'
} else if (support.blob && Blob.prototype.isPrototypeOf(body)) {
this._bodyBlob = body
if (body.type !== '') {
return body.type
}
} else if (support.formData && FormData.prototype.isPrototypeOf(body)) {
this._bodyFormData = body
// Since we don't know what the multipart/form-data boundary string
// will be, we can't set a Content-Type here
} else if (!body) {
this._bodyText = ''
} else if (support.arrayBuffer && ArrayBuffer.prototype.isPrototypeOf(body)) {
......@@ -207,6 +213,7 @@
function Request(input, options) {
options = options || {}
var body = options.body
var bodyFromOptions = true
if (Request.prototype.isPrototypeOf(input)) {
if (input.bodyUsed) {
throw new TypeError('Already read')
......@@ -221,6 +228,7 @@
if (!body) {
body = input._bodyInit
input.bodyUsed = true
bodyFromOptions = false
}
} else {
this.url = input
......@@ -237,7 +245,10 @@
if ((this.method === 'GET' || this.method === 'HEAD') && body) {
throw new TypeError('Body not allowed for GET or HEAD requests')
}
this._initBody(body)
var contentType = this._initBody(body)
if (bodyFromOptions && contentType && !this.headers.get('Content-Type')) {
this.headers.set('Content-Type', contentType)
}
}
Request.prototype.clone = function() {
......@@ -276,12 +287,15 @@
options = {}
}
this._initBody(bodyInit)
this.headers = options.headers instanceof Headers ? options.headers : new Headers(options.headers)
var contentType = this._initBody(bodyInit)
if (contentType && !this.headers.get('Content-Type')) {
this.headers.set('Content-Type', contentType)
}
this.type = 'default'
this.status = options.status
this.ok = this.status >= 200 && this.status < 300
this.statusText = options.statusText
this.headers = options.headers instanceof Headers ? options.headers : new Headers(options.headers)
this.url = options.url || ''
}
......
......@@ -307,6 +307,36 @@ suite('Request', function() {
})
})
test('construct with string body sets Content-Type header', function() {
var req = new Request('https://fetch.spec.whatwg.org/', {
method: 'post',
body: 'I work out'
})
assert.equal(req.headers.get('content-type'), 'text/plain;charset=UTF-8')
})
test('construct with Blob body and type sets Content-Type header', function() {
var req = new Request('https://fetch.spec.whatwg.org/', {
method: 'post',
body: new Blob(['test'], { type: 'text/plain' }),
})
assert.equal(req.headers.get('content-type'), 'text/plain')
})
test('construct with body and explicit header uses header', function() {
var req = new Request('https://fetch.spec.whatwg.org/', {
method: 'post',
headers: {
'Content-Type': 'text/plain'
},
body: 'I work out'
})
assert.equal(req.headers.get('content-type'), 'text/plain')
})
test('clone request', function() {
var req = new Request('https://fetch.spec.whatwg.org/', {
method: 'post',
......@@ -479,6 +509,26 @@ suite('Response', function() {
assert.equal(r.status, 301)
assert.equal(r.headers.get('Location'), 'https://fetch.spec.whatwg.org/')
})
test('construct with string body sets Content-Type header', function() {
var r = new Response('I work out')
assert.equal(r.headers.get('content-type'), 'text/plain;charset=UTF-8')
})
test('construct with Blob body and type sets Content-Type header', function() {
var r = new Response(new Blob(['test'], { type: 'text/plain' }))
assert.equal(r.headers.get('content-type'), 'text/plain')
})
test('construct with body and explicit header uses header', function() {
var r = new Response('I work out', {
headers: {
'Content-Type': 'text/plain'
},
})
assert.equal(r.headers.get('content-type'), 'text/plain')
})
})
// https://fetch.spec.whatwg.org/#body-mixin
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册