More exact content-type and content-length
Set content-type of requests with body being objects to text/plain
This commit is contained in:
parent
385ca6b2b0
commit
a604069860
97
src/body.js
97
src/body.js
|
@ -27,8 +27,21 @@ export default class Body {
|
|||
size = 0,
|
||||
timeout = 0
|
||||
} = {}) {
|
||||
if (body instanceof Blob) {
|
||||
body = body[BUFFER];
|
||||
if (body == null) {
|
||||
// body is undefined or null
|
||||
body = null;
|
||||
} else if (typeof body === 'string') {
|
||||
// body is string
|
||||
} else if (body instanceof Blob) {
|
||||
// body is blob
|
||||
} else if (Buffer.isBuffer(body)) {
|
||||
// body is buffer
|
||||
} else if (bodyStream(body)) {
|
||||
// body is stream
|
||||
} else {
|
||||
// none of the above
|
||||
// coerce to string
|
||||
body = String(body);
|
||||
}
|
||||
this.body = body;
|
||||
this[DISTURBED] = false;
|
||||
|
@ -117,7 +130,7 @@ export default class Body {
|
|||
this[DISTURBED] = true;
|
||||
|
||||
// body is null
|
||||
if (!this.body) {
|
||||
if (this.body === null) {
|
||||
return Body.Promise.resolve(new Buffer(0));
|
||||
}
|
||||
|
||||
|
@ -126,11 +139,21 @@ export default class Body {
|
|||
return Body.Promise.resolve(new Buffer(this.body));
|
||||
}
|
||||
|
||||
// body is blob
|
||||
if (this.body instanceof Blob) {
|
||||
return Body.Promise.resolve(this.body[BUFFER]);
|
||||
}
|
||||
|
||||
// body is buffer
|
||||
if (Buffer.isBuffer(this.body)) {
|
||||
return Body.Promise.resolve(this.body);
|
||||
}
|
||||
|
||||
// should never happen
|
||||
if (!bodyStream(this.body)) {
|
||||
return Body.Promise.resolve(new Buffer(0));
|
||||
}
|
||||
|
||||
// body is stream
|
||||
// get ready to actually consume the body
|
||||
let accum = [];
|
||||
|
@ -281,30 +304,80 @@ export function clone(instance) {
|
|||
* @param Mixed instance Response or Request instance
|
||||
*/
|
||||
export function extractContentType(instance) {
|
||||
// detect form data input from form-data module
|
||||
if (typeof instance.body.getBoundary === 'function') {
|
||||
return `multipart/form-data;boundary=${instance.body.getBoundary()}`;
|
||||
}
|
||||
const {body} = instance;
|
||||
|
||||
if (typeof instance.body === 'string') {
|
||||
if (body === null) {
|
||||
// body is null
|
||||
return null;
|
||||
} else if (typeof body === 'string') {
|
||||
// body is string
|
||||
return 'text/plain;charset=UTF-8';
|
||||
} else if (body instanceof Blob) {
|
||||
// body is blob
|
||||
return body.type || null;
|
||||
} else if (Buffer.isBuffer(body)) {
|
||||
// body is buffer
|
||||
return null;
|
||||
} else if (typeof body.getBoundary === 'function') {
|
||||
// detect form data input from form-data module
|
||||
return `multipart/form-data;boundary=${body.getBoundary()}`;
|
||||
} else {
|
||||
// body is stream
|
||||
// can't really do much about this
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
export function getTotalBytes(instance) {
|
||||
const {body} = instance;
|
||||
|
||||
if (typeof body === 'string') {
|
||||
if (body === null) {
|
||||
// body is null
|
||||
return 0;
|
||||
} else if (typeof body === 'string') {
|
||||
// body is string
|
||||
return Buffer.byteLength(body);
|
||||
} else if (body instanceof Blob) {
|
||||
// body is blob
|
||||
return body.size;
|
||||
} else if (body && typeof body.getLengthSync === 'function') {
|
||||
// detect form data input from form-data module
|
||||
if (body._lengthRetrievers && body._lengthRetrievers.length == 0 || // 1.x
|
||||
body.hasKnownLength && body.hasKnownLength()) { // 2.x
|
||||
return body.getLengthSync();
|
||||
}
|
||||
} else if (body === undefined || body === null) {
|
||||
// this is only necessary for older nodejs releases (before iojs merge)
|
||||
return 0;
|
||||
return null;
|
||||
} else {
|
||||
// body is stream
|
||||
// can't really do much about this
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
export function writeToStream(dest, instance) {
|
||||
const {body} = instance;
|
||||
|
||||
if (body === null) {
|
||||
// body is null
|
||||
dest.end();
|
||||
} else if (typeof body === 'string') {
|
||||
// body is string
|
||||
dest.write(body);
|
||||
dest.end();
|
||||
} else if (body instanceof Blob) {
|
||||
// body is blob
|
||||
dest.write(body[BUFFER]);
|
||||
dest.end();
|
||||
} else if (Buffer.isBuffer(body)) {
|
||||
// body is buffer
|
||||
dest.write(body);
|
||||
dest.end()
|
||||
} else if (bodyStream(body)) {
|
||||
// body is stream
|
||||
body.pipe(dest);
|
||||
} else {
|
||||
// should never happen
|
||||
dest.end();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
19
src/index.js
19
src/index.js
|
@ -11,7 +11,7 @@ import * as https from 'https';
|
|||
import * as zlib from 'zlib';
|
||||
import {PassThrough} from 'stream';
|
||||
|
||||
import Body from './body';
|
||||
import Body, { writeToStream } from './body';
|
||||
import Response from './response';
|
||||
import Headers from './headers';
|
||||
import Request, { getNodeRequestOptions } from './request';
|
||||
|
@ -184,22 +184,7 @@ function fetch(url, opts) {
|
|||
return;
|
||||
});
|
||||
|
||||
// accept string, buffer, readable stream or null as body
|
||||
// per spec we will call tostring on non-stream objects
|
||||
if (typeof request.body === 'string') {
|
||||
req.write(request.body);
|
||||
req.end();
|
||||
} else if (request.body instanceof Buffer) {
|
||||
req.write(request.body);
|
||||
req.end()
|
||||
} else if (request.body && typeof request.body === 'object' && request.body.pipe) {
|
||||
request.body.pipe(req);
|
||||
} else if (request.body && typeof request.body === 'object') {
|
||||
req.write(request.body.toString());
|
||||
req.end();
|
||||
} else {
|
||||
req.end();
|
||||
}
|
||||
writeToStream(req, request);
|
||||
});
|
||||
|
||||
};
|
||||
|
|
|
@ -63,7 +63,7 @@ export default class Request extends Body {
|
|||
|
||||
if (init.body != null) {
|
||||
const contentType = extractContentType(this);
|
||||
if (contentType && !this.headers.has('Content-Type')) {
|
||||
if (contentType !== null && !this.headers.has('Content-Type')) {
|
||||
this.headers.append('Content-Type', contentType);
|
||||
}
|
||||
}
|
||||
|
|
10
test/test.js
10
test/test.js
|
@ -814,6 +814,8 @@ describe(`node-fetch with FOLLOW_SPEC = ${defaultFollowSpec}`, () => {
|
|||
}).then(res => {
|
||||
expect(res.method).to.equal('POST');
|
||||
expect(res.body).to.equal('[object Object]');
|
||||
expect(res.headers['content-type']).to.equal('text/plain;charset=UTF-8');
|
||||
expect(res.headers['content-length']).to.equal('15');
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -1446,14 +1448,20 @@ describe(`node-fetch with FOLLOW_SPEC = ${defaultFollowSpec}`, () => {
|
|||
it('should support blob round-trip', function() {
|
||||
url = `${base}hello`;
|
||||
|
||||
let length, type;
|
||||
|
||||
return fetch(url).then(res => res.blob()).then(blob => {
|
||||
url = `${base}inspect`;
|
||||
length = blob.size;
|
||||
type = blob.type;
|
||||
return fetch(url, {
|
||||
method: 'POST',
|
||||
body: blob
|
||||
});
|
||||
}).then(res => res.json()).then(({body}) => {
|
||||
}).then(res => res.json()).then(({body, headers}) => {
|
||||
expect(body).to.equal('world');
|
||||
expect(headers['content-type']).to.equal(type);
|
||||
expect(headers['content-length']).to.equal(String(length));
|
||||
});
|
||||
});
|
||||
|
||||
|
|
Loading…
Reference in New Issue