Bez popisu

Fetch.js 6.2KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214
  1. import RNFetchBlob from '../index.js'
  2. import Log from '../utils/log.js'
  3. import fs from '../fs'
  4. import unicode from '../utils/unicode'
  5. import Blob from './Blob'
  6. const log = new Log('FetchPolyfill')
  7. log.disable()
  8. // log.level(3)
  9. export default class Fetch {
  10. constructor(config:RNFetchBlobConfig) {
  11. Object.assign(this, new RNFetchBlobFetchPolyfill(config))
  12. }
  13. }
  14. class RNFetchBlobFetchPolyfill {
  15. constructor(config:RNFetchBlobConfig) {
  16. this.build = () => (url, options = {}) => {
  17. let body = options.body
  18. let promise = Promise.resolve()
  19. let blobCache = null
  20. options.headers = options.headers || {}
  21. let ctype = options['Content-Type'] || options['content-type']
  22. let ctypeH = options.headers['Content-Type'] || options.headers['content-type']
  23. options.headers['Content-Type'] = ctype || ctypeH
  24. options.headers['content-type'] = ctype || ctypeH
  25. options.method = options.method || 'GET'
  26. if(body) {
  27. // When the request body is an instance of FormData, create a Blob cache
  28. // to upload the body.
  29. if(body instanceof FormData) {
  30. log.verbose('convert FormData to blob body')
  31. promise = Blob.build(body).then((b) => {
  32. blobCache = b
  33. options.headers['Content-Type'] = 'multipart/form-data;boundary=' + b.multipartBoundary
  34. return Promise.resolve(RNFetchBlob.wrap(b._ref))
  35. })
  36. }
  37. // When request body is a Blob, use file URI of the Blob as request body.
  38. else if (body.isRNFetchBlobPolyfill)
  39. promise = Promise.resolve(RNFetchBlob.wrap(body.blobPath))
  40. else if (typeof body !== 'object' && options.headers['Content-Type'] !== 'application/json')
  41. promise = Promise.resolve(JSON.stringify(body))
  42. else if (typeof body !== 'string')
  43. promise = Promise.resolve(body.toString())
  44. // send it as-is, leave the native module decide how to send the body.
  45. else
  46. promise = Promise.resolve(body)
  47. }
  48. // task is a progress reportable and cancellable Promise, however,
  49. // task.then is not, so we have to extend task.then with progress and
  50. // cancel function
  51. let progressHandler, uploadHandler, cancelHandler
  52. let statefulPromise = promise
  53. .then((body) => {
  54. let task = RNFetchBlob.config(config)
  55. .fetch(options.method, url, options.headers, body)
  56. if(progressHandler)
  57. task.progress(progressHandler)
  58. if(uploadHandler)
  59. task.uploadProgress(uploadHandler)
  60. if(cancelHandler)
  61. task.cancel()
  62. return task.then((resp) => {
  63. log.verbose('response', resp)
  64. // release blob cache created when sending request
  65. if(blobCache !== null && blobCache instanceof Blob)
  66. blobCache.close()
  67. return Promise.resolve(new RNFetchBlobFetchResponse(resp))
  68. })
  69. })
  70. // extend task.then progress with report and cancelling functions
  71. statefulPromise.progress = (fn) => {
  72. progressHandler = fn
  73. }
  74. statefulPromise.uploadProgress = (fn) => {
  75. uploadHandler = fn
  76. }
  77. statefulPromise.cancel = () => {
  78. cancelHandler = true
  79. if(task.cancel)
  80. task.cancel()
  81. }
  82. return statefulPromise
  83. }
  84. }
  85. }
  86. class RNFetchBlobFetchResponse {
  87. constructor(resp:FetchBlobResponse) {
  88. let info = resp.info()
  89. this.headers = info.headers
  90. this.ok = info.status >= 200 && info.status <= 299,
  91. this.status = info.status
  92. this.type = 'basic'
  93. this.bodyUsed = false
  94. this.resp = resp
  95. this.rnfbRespInfo = info
  96. this.rnfbResp = resp
  97. }
  98. rawResp() {
  99. return Promise.resolve(this.rnfbResp)
  100. }
  101. arrayBuffer(){
  102. log.verbose('to arrayBuffer', this.rnfbRespInfo)
  103. this.bodyUsed = true
  104. return readArrayBuffer(this.rnfbResp, this.rnfbRespInfo)
  105. }
  106. text() {
  107. log.verbose('to text', this.rnfbResp, this.rnfbRespInfo)
  108. this.bodyUsed = true
  109. return readText(this.rnfbResp, this.rnfbRespInfo)
  110. }
  111. json() {
  112. log.verbose('to json', this.rnfbResp, this.rnfbRespInfo)
  113. this.bodyUsed = true
  114. return readJSON(this.rnfbResp, this.rnfbRespInfo)
  115. }
  116. blob() {
  117. log.verbose('to blob', this.rnfbResp, this.rnfbRespInfo)
  118. this.bodyUsed = true
  119. return readBlob(this.rnfbResp, this.rnfbRespInfo)
  120. }
  121. }
  122. /**
  123. * Get response data as array.
  124. * @param {FetchBlobResponse} resp Response data object from RNFB fetch call.
  125. * @param {RNFetchBlobResponseInfo} info Response informations.
  126. * @return {Promise<Array>}
  127. */
  128. function readArrayBuffer(resp, info):Promise<Array> {
  129. switch (info.rnfbEncode) {
  130. case 'path':
  131. return resp.readFile('ascii')
  132. break
  133. default:
  134. let buffer = []
  135. let str = resp.text()
  136. for (let i in str) {
  137. buffer[i] = str.charCodeAt(i);
  138. }
  139. return Promise.resolve(buffer)
  140. break
  141. }
  142. }
  143. /**
  144. * Get response data as string.
  145. * @param {FetchBlobResponse} resp Response data object from RNFB fetch call.
  146. * @param {RNFetchBlobResponseInfo} info Response informations.
  147. * @return {Promise<string>}
  148. */
  149. function readText(resp, info):Promise<string> {
  150. switch (info.rnfbEncode) {
  151. case 'base64':
  152. return Promise.resolve(resp.text())
  153. break
  154. case 'path':
  155. return resp.text()
  156. break
  157. default:
  158. return Promise.resolve(resp.text())
  159. break
  160. }
  161. }
  162. /**
  163. * Get response data as RNFetchBlob Blob polyfill object.
  164. * @param {FetchBlobResponse} resp Response data object from RNFB fetch call.
  165. * @param {RNFetchBlobResponseInfo} info Response informations.
  166. * @return {Promise<Blob>}
  167. */
  168. function readBlob(resp, info):Promise<Blob> {
  169. log.verbose('readBlob', resp, info)
  170. return resp.blob()
  171. }
  172. /**
  173. * Get response data as JSON object.
  174. * @param {FetchBlobResponse} resp Response data object from RNFB fetch call.
  175. * @param {RNFetchBlobResponseInfo} info Response informations.
  176. * @return {Promise<object>}
  177. */
  178. function readJSON(resp, info):Promise<object> {
  179. log.verbose('readJSON', resp, info)
  180. switch (info.rnfbEncode) {
  181. case 'base64':
  182. return Promise.resolve(resp.json())
  183. case 'path':
  184. return resp.json()
  185. default:
  186. return Promise.resolve(resp.json())
  187. }
  188. }