11cb0ef41Sopenharmony_ci'use strict' 21cb0ef41Sopenharmony_ciconst { Minipass } = require('minipass') 31cb0ef41Sopenharmony_ciconst MinipassSized = require('minipass-sized') 41cb0ef41Sopenharmony_ci 51cb0ef41Sopenharmony_ciconst Blob = require('./blob.js') 61cb0ef41Sopenharmony_ciconst { BUFFER } = Blob 71cb0ef41Sopenharmony_ciconst FetchError = require('./fetch-error.js') 81cb0ef41Sopenharmony_ci 91cb0ef41Sopenharmony_ci// optional dependency on 'encoding' 101cb0ef41Sopenharmony_cilet convert 111cb0ef41Sopenharmony_citry { 121cb0ef41Sopenharmony_ci convert = require('encoding').convert 131cb0ef41Sopenharmony_ci} catch (e) { 141cb0ef41Sopenharmony_ci // defer error until textConverted is called 151cb0ef41Sopenharmony_ci} 161cb0ef41Sopenharmony_ci 171cb0ef41Sopenharmony_ciconst INTERNALS = Symbol('Body internals') 181cb0ef41Sopenharmony_ciconst CONSUME_BODY = Symbol('consumeBody') 191cb0ef41Sopenharmony_ci 201cb0ef41Sopenharmony_ciclass Body { 211cb0ef41Sopenharmony_ci constructor (bodyArg, options = {}) { 221cb0ef41Sopenharmony_ci const { size = 0, timeout = 0 } = options 231cb0ef41Sopenharmony_ci const body = bodyArg === undefined || bodyArg === null ? null 241cb0ef41Sopenharmony_ci : isURLSearchParams(bodyArg) ? Buffer.from(bodyArg.toString()) 251cb0ef41Sopenharmony_ci : isBlob(bodyArg) ? bodyArg 261cb0ef41Sopenharmony_ci : Buffer.isBuffer(bodyArg) ? bodyArg 271cb0ef41Sopenharmony_ci : Object.prototype.toString.call(bodyArg) === '[object ArrayBuffer]' 281cb0ef41Sopenharmony_ci ? Buffer.from(bodyArg) 291cb0ef41Sopenharmony_ci : ArrayBuffer.isView(bodyArg) 301cb0ef41Sopenharmony_ci ? Buffer.from(bodyArg.buffer, bodyArg.byteOffset, bodyArg.byteLength) 311cb0ef41Sopenharmony_ci : Minipass.isStream(bodyArg) ? bodyArg 321cb0ef41Sopenharmony_ci : Buffer.from(String(bodyArg)) 331cb0ef41Sopenharmony_ci 341cb0ef41Sopenharmony_ci this[INTERNALS] = { 351cb0ef41Sopenharmony_ci body, 361cb0ef41Sopenharmony_ci disturbed: false, 371cb0ef41Sopenharmony_ci error: null, 381cb0ef41Sopenharmony_ci } 391cb0ef41Sopenharmony_ci 401cb0ef41Sopenharmony_ci this.size = size 411cb0ef41Sopenharmony_ci this.timeout = timeout 421cb0ef41Sopenharmony_ci 431cb0ef41Sopenharmony_ci if (Minipass.isStream(body)) { 441cb0ef41Sopenharmony_ci body.on('error', er => { 451cb0ef41Sopenharmony_ci const error = er.name === 'AbortError' ? er 461cb0ef41Sopenharmony_ci : new FetchError(`Invalid response while trying to fetch ${ 471cb0ef41Sopenharmony_ci this.url}: ${er.message}`, 'system', er) 481cb0ef41Sopenharmony_ci this[INTERNALS].error = error 491cb0ef41Sopenharmony_ci }) 501cb0ef41Sopenharmony_ci } 511cb0ef41Sopenharmony_ci } 521cb0ef41Sopenharmony_ci 531cb0ef41Sopenharmony_ci get body () { 541cb0ef41Sopenharmony_ci return this[INTERNALS].body 551cb0ef41Sopenharmony_ci } 561cb0ef41Sopenharmony_ci 571cb0ef41Sopenharmony_ci get bodyUsed () { 581cb0ef41Sopenharmony_ci return this[INTERNALS].disturbed 591cb0ef41Sopenharmony_ci } 601cb0ef41Sopenharmony_ci 611cb0ef41Sopenharmony_ci arrayBuffer () { 621cb0ef41Sopenharmony_ci return this[CONSUME_BODY]().then(buf => 631cb0ef41Sopenharmony_ci buf.buffer.slice(buf.byteOffset, buf.byteOffset + buf.byteLength)) 641cb0ef41Sopenharmony_ci } 651cb0ef41Sopenharmony_ci 661cb0ef41Sopenharmony_ci blob () { 671cb0ef41Sopenharmony_ci const ct = this.headers && this.headers.get('content-type') || '' 681cb0ef41Sopenharmony_ci return this[CONSUME_BODY]().then(buf => Object.assign( 691cb0ef41Sopenharmony_ci new Blob([], { type: ct.toLowerCase() }), 701cb0ef41Sopenharmony_ci { [BUFFER]: buf } 711cb0ef41Sopenharmony_ci )) 721cb0ef41Sopenharmony_ci } 731cb0ef41Sopenharmony_ci 741cb0ef41Sopenharmony_ci async json () { 751cb0ef41Sopenharmony_ci const buf = await this[CONSUME_BODY]() 761cb0ef41Sopenharmony_ci try { 771cb0ef41Sopenharmony_ci return JSON.parse(buf.toString()) 781cb0ef41Sopenharmony_ci } catch (er) { 791cb0ef41Sopenharmony_ci throw new FetchError( 801cb0ef41Sopenharmony_ci `invalid json response body at ${this.url} reason: ${er.message}`, 811cb0ef41Sopenharmony_ci 'invalid-json' 821cb0ef41Sopenharmony_ci ) 831cb0ef41Sopenharmony_ci } 841cb0ef41Sopenharmony_ci } 851cb0ef41Sopenharmony_ci 861cb0ef41Sopenharmony_ci text () { 871cb0ef41Sopenharmony_ci return this[CONSUME_BODY]().then(buf => buf.toString()) 881cb0ef41Sopenharmony_ci } 891cb0ef41Sopenharmony_ci 901cb0ef41Sopenharmony_ci buffer () { 911cb0ef41Sopenharmony_ci return this[CONSUME_BODY]() 921cb0ef41Sopenharmony_ci } 931cb0ef41Sopenharmony_ci 941cb0ef41Sopenharmony_ci textConverted () { 951cb0ef41Sopenharmony_ci return this[CONSUME_BODY]().then(buf => convertBody(buf, this.headers)) 961cb0ef41Sopenharmony_ci } 971cb0ef41Sopenharmony_ci 981cb0ef41Sopenharmony_ci [CONSUME_BODY] () { 991cb0ef41Sopenharmony_ci if (this[INTERNALS].disturbed) { 1001cb0ef41Sopenharmony_ci return Promise.reject(new TypeError(`body used already for: ${ 1011cb0ef41Sopenharmony_ci this.url}`)) 1021cb0ef41Sopenharmony_ci } 1031cb0ef41Sopenharmony_ci 1041cb0ef41Sopenharmony_ci this[INTERNALS].disturbed = true 1051cb0ef41Sopenharmony_ci 1061cb0ef41Sopenharmony_ci if (this[INTERNALS].error) { 1071cb0ef41Sopenharmony_ci return Promise.reject(this[INTERNALS].error) 1081cb0ef41Sopenharmony_ci } 1091cb0ef41Sopenharmony_ci 1101cb0ef41Sopenharmony_ci // body is null 1111cb0ef41Sopenharmony_ci if (this.body === null) { 1121cb0ef41Sopenharmony_ci return Promise.resolve(Buffer.alloc(0)) 1131cb0ef41Sopenharmony_ci } 1141cb0ef41Sopenharmony_ci 1151cb0ef41Sopenharmony_ci if (Buffer.isBuffer(this.body)) { 1161cb0ef41Sopenharmony_ci return Promise.resolve(this.body) 1171cb0ef41Sopenharmony_ci } 1181cb0ef41Sopenharmony_ci 1191cb0ef41Sopenharmony_ci const upstream = isBlob(this.body) ? this.body.stream() : this.body 1201cb0ef41Sopenharmony_ci 1211cb0ef41Sopenharmony_ci /* istanbul ignore if: should never happen */ 1221cb0ef41Sopenharmony_ci if (!Minipass.isStream(upstream)) { 1231cb0ef41Sopenharmony_ci return Promise.resolve(Buffer.alloc(0)) 1241cb0ef41Sopenharmony_ci } 1251cb0ef41Sopenharmony_ci 1261cb0ef41Sopenharmony_ci const stream = this.size && upstream instanceof MinipassSized ? upstream 1271cb0ef41Sopenharmony_ci : !this.size && upstream instanceof Minipass && 1281cb0ef41Sopenharmony_ci !(upstream instanceof MinipassSized) ? upstream 1291cb0ef41Sopenharmony_ci : this.size ? new MinipassSized({ size: this.size }) 1301cb0ef41Sopenharmony_ci : new Minipass() 1311cb0ef41Sopenharmony_ci 1321cb0ef41Sopenharmony_ci // allow timeout on slow response body, but only if the stream is still writable. this 1331cb0ef41Sopenharmony_ci // makes the timeout center on the socket stream from lib/index.js rather than the 1341cb0ef41Sopenharmony_ci // intermediary minipass stream we create to receive the data 1351cb0ef41Sopenharmony_ci const resTimeout = this.timeout && stream.writable ? setTimeout(() => { 1361cb0ef41Sopenharmony_ci stream.emit('error', new FetchError( 1371cb0ef41Sopenharmony_ci `Response timeout while trying to fetch ${ 1381cb0ef41Sopenharmony_ci this.url} (over ${this.timeout}ms)`, 'body-timeout')) 1391cb0ef41Sopenharmony_ci }, this.timeout) : null 1401cb0ef41Sopenharmony_ci 1411cb0ef41Sopenharmony_ci // do not keep the process open just for this timeout, even 1421cb0ef41Sopenharmony_ci // though we expect it'll get cleared eventually. 1431cb0ef41Sopenharmony_ci if (resTimeout && resTimeout.unref) { 1441cb0ef41Sopenharmony_ci resTimeout.unref() 1451cb0ef41Sopenharmony_ci } 1461cb0ef41Sopenharmony_ci 1471cb0ef41Sopenharmony_ci // do the pipe in the promise, because the pipe() can send too much 1481cb0ef41Sopenharmony_ci // data through right away and upset the MP Sized object 1491cb0ef41Sopenharmony_ci return new Promise((resolve, reject) => { 1501cb0ef41Sopenharmony_ci // if the stream is some other kind of stream, then pipe through a MP 1511cb0ef41Sopenharmony_ci // so we can collect it more easily. 1521cb0ef41Sopenharmony_ci if (stream !== upstream) { 1531cb0ef41Sopenharmony_ci upstream.on('error', er => stream.emit('error', er)) 1541cb0ef41Sopenharmony_ci upstream.pipe(stream) 1551cb0ef41Sopenharmony_ci } 1561cb0ef41Sopenharmony_ci resolve() 1571cb0ef41Sopenharmony_ci }).then(() => stream.concat()).then(buf => { 1581cb0ef41Sopenharmony_ci clearTimeout(resTimeout) 1591cb0ef41Sopenharmony_ci return buf 1601cb0ef41Sopenharmony_ci }).catch(er => { 1611cb0ef41Sopenharmony_ci clearTimeout(resTimeout) 1621cb0ef41Sopenharmony_ci // request was aborted, reject with this Error 1631cb0ef41Sopenharmony_ci if (er.name === 'AbortError' || er.name === 'FetchError') { 1641cb0ef41Sopenharmony_ci throw er 1651cb0ef41Sopenharmony_ci } else if (er.name === 'RangeError') { 1661cb0ef41Sopenharmony_ci throw new FetchError(`Could not create Buffer from response body for ${ 1671cb0ef41Sopenharmony_ci this.url}: ${er.message}`, 'system', er) 1681cb0ef41Sopenharmony_ci } else { 1691cb0ef41Sopenharmony_ci // other errors, such as incorrect content-encoding or content-length 1701cb0ef41Sopenharmony_ci throw new FetchError(`Invalid response body while trying to fetch ${ 1711cb0ef41Sopenharmony_ci this.url}: ${er.message}`, 'system', er) 1721cb0ef41Sopenharmony_ci } 1731cb0ef41Sopenharmony_ci }) 1741cb0ef41Sopenharmony_ci } 1751cb0ef41Sopenharmony_ci 1761cb0ef41Sopenharmony_ci static clone (instance) { 1771cb0ef41Sopenharmony_ci if (instance.bodyUsed) { 1781cb0ef41Sopenharmony_ci throw new Error('cannot clone body after it is used') 1791cb0ef41Sopenharmony_ci } 1801cb0ef41Sopenharmony_ci 1811cb0ef41Sopenharmony_ci const body = instance.body 1821cb0ef41Sopenharmony_ci 1831cb0ef41Sopenharmony_ci // check that body is a stream and not form-data object 1841cb0ef41Sopenharmony_ci // NB: can't clone the form-data object without having it as a dependency 1851cb0ef41Sopenharmony_ci if (Minipass.isStream(body) && typeof body.getBoundary !== 'function') { 1861cb0ef41Sopenharmony_ci // create a dedicated tee stream so that we don't lose data 1871cb0ef41Sopenharmony_ci // potentially sitting in the body stream's buffer by writing it 1881cb0ef41Sopenharmony_ci // immediately to p1 and not having it for p2. 1891cb0ef41Sopenharmony_ci const tee = new Minipass() 1901cb0ef41Sopenharmony_ci const p1 = new Minipass() 1911cb0ef41Sopenharmony_ci const p2 = new Minipass() 1921cb0ef41Sopenharmony_ci tee.on('error', er => { 1931cb0ef41Sopenharmony_ci p1.emit('error', er) 1941cb0ef41Sopenharmony_ci p2.emit('error', er) 1951cb0ef41Sopenharmony_ci }) 1961cb0ef41Sopenharmony_ci body.on('error', er => tee.emit('error', er)) 1971cb0ef41Sopenharmony_ci tee.pipe(p1) 1981cb0ef41Sopenharmony_ci tee.pipe(p2) 1991cb0ef41Sopenharmony_ci body.pipe(tee) 2001cb0ef41Sopenharmony_ci // set instance body to one fork, return the other 2011cb0ef41Sopenharmony_ci instance[INTERNALS].body = p1 2021cb0ef41Sopenharmony_ci return p2 2031cb0ef41Sopenharmony_ci } else { 2041cb0ef41Sopenharmony_ci return instance.body 2051cb0ef41Sopenharmony_ci } 2061cb0ef41Sopenharmony_ci } 2071cb0ef41Sopenharmony_ci 2081cb0ef41Sopenharmony_ci static extractContentType (body) { 2091cb0ef41Sopenharmony_ci return body === null || body === undefined ? null 2101cb0ef41Sopenharmony_ci : typeof body === 'string' ? 'text/plain;charset=UTF-8' 2111cb0ef41Sopenharmony_ci : isURLSearchParams(body) 2121cb0ef41Sopenharmony_ci ? 'application/x-www-form-urlencoded;charset=UTF-8' 2131cb0ef41Sopenharmony_ci : isBlob(body) ? body.type || null 2141cb0ef41Sopenharmony_ci : Buffer.isBuffer(body) ? null 2151cb0ef41Sopenharmony_ci : Object.prototype.toString.call(body) === '[object ArrayBuffer]' ? null 2161cb0ef41Sopenharmony_ci : ArrayBuffer.isView(body) ? null 2171cb0ef41Sopenharmony_ci : typeof body.getBoundary === 'function' 2181cb0ef41Sopenharmony_ci ? `multipart/form-data;boundary=${body.getBoundary()}` 2191cb0ef41Sopenharmony_ci : Minipass.isStream(body) ? null 2201cb0ef41Sopenharmony_ci : 'text/plain;charset=UTF-8' 2211cb0ef41Sopenharmony_ci } 2221cb0ef41Sopenharmony_ci 2231cb0ef41Sopenharmony_ci static getTotalBytes (instance) { 2241cb0ef41Sopenharmony_ci const { body } = instance 2251cb0ef41Sopenharmony_ci return (body === null || body === undefined) ? 0 2261cb0ef41Sopenharmony_ci : isBlob(body) ? body.size 2271cb0ef41Sopenharmony_ci : Buffer.isBuffer(body) ? body.length 2281cb0ef41Sopenharmony_ci : body && typeof body.getLengthSync === 'function' && ( 2291cb0ef41Sopenharmony_ci // detect form data input from form-data module 2301cb0ef41Sopenharmony_ci body._lengthRetrievers && 2311cb0ef41Sopenharmony_ci /* istanbul ignore next */ body._lengthRetrievers.length === 0 || // 1.x 2321cb0ef41Sopenharmony_ci body.hasKnownLength && body.hasKnownLength()) // 2.x 2331cb0ef41Sopenharmony_ci ? body.getLengthSync() 2341cb0ef41Sopenharmony_ci : null 2351cb0ef41Sopenharmony_ci } 2361cb0ef41Sopenharmony_ci 2371cb0ef41Sopenharmony_ci static writeToStream (dest, instance) { 2381cb0ef41Sopenharmony_ci const { body } = instance 2391cb0ef41Sopenharmony_ci 2401cb0ef41Sopenharmony_ci if (body === null || body === undefined) { 2411cb0ef41Sopenharmony_ci dest.end() 2421cb0ef41Sopenharmony_ci } else if (Buffer.isBuffer(body) || typeof body === 'string') { 2431cb0ef41Sopenharmony_ci dest.end(body) 2441cb0ef41Sopenharmony_ci } else { 2451cb0ef41Sopenharmony_ci // body is stream or blob 2461cb0ef41Sopenharmony_ci const stream = isBlob(body) ? body.stream() : body 2471cb0ef41Sopenharmony_ci stream.on('error', er => dest.emit('error', er)).pipe(dest) 2481cb0ef41Sopenharmony_ci } 2491cb0ef41Sopenharmony_ci 2501cb0ef41Sopenharmony_ci return dest 2511cb0ef41Sopenharmony_ci } 2521cb0ef41Sopenharmony_ci} 2531cb0ef41Sopenharmony_ci 2541cb0ef41Sopenharmony_ciObject.defineProperties(Body.prototype, { 2551cb0ef41Sopenharmony_ci body: { enumerable: true }, 2561cb0ef41Sopenharmony_ci bodyUsed: { enumerable: true }, 2571cb0ef41Sopenharmony_ci arrayBuffer: { enumerable: true }, 2581cb0ef41Sopenharmony_ci blob: { enumerable: true }, 2591cb0ef41Sopenharmony_ci json: { enumerable: true }, 2601cb0ef41Sopenharmony_ci text: { enumerable: true }, 2611cb0ef41Sopenharmony_ci}) 2621cb0ef41Sopenharmony_ci 2631cb0ef41Sopenharmony_ciconst isURLSearchParams = obj => 2641cb0ef41Sopenharmony_ci // Duck-typing as a necessary condition. 2651cb0ef41Sopenharmony_ci (typeof obj !== 'object' || 2661cb0ef41Sopenharmony_ci typeof obj.append !== 'function' || 2671cb0ef41Sopenharmony_ci typeof obj.delete !== 'function' || 2681cb0ef41Sopenharmony_ci typeof obj.get !== 'function' || 2691cb0ef41Sopenharmony_ci typeof obj.getAll !== 'function' || 2701cb0ef41Sopenharmony_ci typeof obj.has !== 'function' || 2711cb0ef41Sopenharmony_ci typeof obj.set !== 'function') ? false 2721cb0ef41Sopenharmony_ci // Brand-checking and more duck-typing as optional condition. 2731cb0ef41Sopenharmony_ci : obj.constructor.name === 'URLSearchParams' || 2741cb0ef41Sopenharmony_ci Object.prototype.toString.call(obj) === '[object URLSearchParams]' || 2751cb0ef41Sopenharmony_ci typeof obj.sort === 'function' 2761cb0ef41Sopenharmony_ci 2771cb0ef41Sopenharmony_ciconst isBlob = obj => 2781cb0ef41Sopenharmony_ci typeof obj === 'object' && 2791cb0ef41Sopenharmony_ci typeof obj.arrayBuffer === 'function' && 2801cb0ef41Sopenharmony_ci typeof obj.type === 'string' && 2811cb0ef41Sopenharmony_ci typeof obj.stream === 'function' && 2821cb0ef41Sopenharmony_ci typeof obj.constructor === 'function' && 2831cb0ef41Sopenharmony_ci typeof obj.constructor.name === 'string' && 2841cb0ef41Sopenharmony_ci /^(Blob|File)$/.test(obj.constructor.name) && 2851cb0ef41Sopenharmony_ci /^(Blob|File)$/.test(obj[Symbol.toStringTag]) 2861cb0ef41Sopenharmony_ci 2871cb0ef41Sopenharmony_ciconst convertBody = (buffer, headers) => { 2881cb0ef41Sopenharmony_ci /* istanbul ignore if */ 2891cb0ef41Sopenharmony_ci if (typeof convert !== 'function') { 2901cb0ef41Sopenharmony_ci throw new Error('The package `encoding` must be installed to use the textConverted() function') 2911cb0ef41Sopenharmony_ci } 2921cb0ef41Sopenharmony_ci 2931cb0ef41Sopenharmony_ci const ct = headers && headers.get('content-type') 2941cb0ef41Sopenharmony_ci let charset = 'utf-8' 2951cb0ef41Sopenharmony_ci let res 2961cb0ef41Sopenharmony_ci 2971cb0ef41Sopenharmony_ci // header 2981cb0ef41Sopenharmony_ci if (ct) { 2991cb0ef41Sopenharmony_ci res = /charset=([^;]*)/i.exec(ct) 3001cb0ef41Sopenharmony_ci } 3011cb0ef41Sopenharmony_ci 3021cb0ef41Sopenharmony_ci // no charset in content type, peek at response body for at most 1024 bytes 3031cb0ef41Sopenharmony_ci const str = buffer.slice(0, 1024).toString() 3041cb0ef41Sopenharmony_ci 3051cb0ef41Sopenharmony_ci // html5 3061cb0ef41Sopenharmony_ci if (!res && str) { 3071cb0ef41Sopenharmony_ci res = /<meta.+?charset=(['"])(.+?)\1/i.exec(str) 3081cb0ef41Sopenharmony_ci } 3091cb0ef41Sopenharmony_ci 3101cb0ef41Sopenharmony_ci // html4 3111cb0ef41Sopenharmony_ci if (!res && str) { 3121cb0ef41Sopenharmony_ci res = /<meta[\s]+?http-equiv=(['"])content-type\1[\s]+?content=(['"])(.+?)\2/i.exec(str) 3131cb0ef41Sopenharmony_ci 3141cb0ef41Sopenharmony_ci if (!res) { 3151cb0ef41Sopenharmony_ci res = /<meta[\s]+?content=(['"])(.+?)\1[\s]+?http-equiv=(['"])content-type\3/i.exec(str) 3161cb0ef41Sopenharmony_ci if (res) { 3171cb0ef41Sopenharmony_ci res.pop() 3181cb0ef41Sopenharmony_ci } // drop last quote 3191cb0ef41Sopenharmony_ci } 3201cb0ef41Sopenharmony_ci 3211cb0ef41Sopenharmony_ci if (res) { 3221cb0ef41Sopenharmony_ci res = /charset=(.*)/i.exec(res.pop()) 3231cb0ef41Sopenharmony_ci } 3241cb0ef41Sopenharmony_ci } 3251cb0ef41Sopenharmony_ci 3261cb0ef41Sopenharmony_ci // xml 3271cb0ef41Sopenharmony_ci if (!res && str) { 3281cb0ef41Sopenharmony_ci res = /<\?xml.+?encoding=(['"])(.+?)\1/i.exec(str) 3291cb0ef41Sopenharmony_ci } 3301cb0ef41Sopenharmony_ci 3311cb0ef41Sopenharmony_ci // found charset 3321cb0ef41Sopenharmony_ci if (res) { 3331cb0ef41Sopenharmony_ci charset = res.pop() 3341cb0ef41Sopenharmony_ci 3351cb0ef41Sopenharmony_ci // prevent decode issues when sites use incorrect encoding 3361cb0ef41Sopenharmony_ci // ref: https://hsivonen.fi/encoding-menu/ 3371cb0ef41Sopenharmony_ci if (charset === 'gb2312' || charset === 'gbk') { 3381cb0ef41Sopenharmony_ci charset = 'gb18030' 3391cb0ef41Sopenharmony_ci } 3401cb0ef41Sopenharmony_ci } 3411cb0ef41Sopenharmony_ci 3421cb0ef41Sopenharmony_ci // turn raw buffers into a single utf-8 buffer 3431cb0ef41Sopenharmony_ci return convert( 3441cb0ef41Sopenharmony_ci buffer, 3451cb0ef41Sopenharmony_ci 'UTF-8', 3461cb0ef41Sopenharmony_ci charset 3471cb0ef41Sopenharmony_ci ).toString() 3481cb0ef41Sopenharmony_ci} 3491cb0ef41Sopenharmony_ci 3501cb0ef41Sopenharmony_cimodule.exports = Body 351