1 | var middleware = require('./middleware')
|
2 |
|
3 | function toUpperCase (x) {
|
4 | return x.toUpperCase()
|
5 | }
|
6 |
|
7 | function formatHeaderName (name) {
|
8 | return name.replace(/^([a-z])/, toUpperCase).replace(/-([a-z])/g, toUpperCase)
|
9 | }
|
10 |
|
11 | function setHeaders (headers, xhr) {
|
12 | var headerNames = Object.keys(headers)
|
13 |
|
14 | for (var n = 0; n < headerNames.length; n++) {
|
15 | var key = headerNames[n]
|
16 | var headerName = formatHeaderName(key)
|
17 | xhr.setRequestHeader(headerName, headers[key])
|
18 | }
|
19 | }
|
20 |
|
21 | function isCrossDomain (url) {
|
22 | return /^https?:\/\//.test(url)
|
23 | }
|
24 |
|
25 | function responseUrl (xhr, requestUrl) {
|
26 | var origin = window.location.origin
|
27 | var responseUrl = xhr.responseURL
|
28 |
|
29 | if (responseUrl) {
|
30 | if (responseUrl.substring(0, origin.length) === origin) {
|
31 | return responseUrl.substring(origin.length)
|
32 | } else {
|
33 | return responseUrl
|
34 | }
|
35 | } else {
|
36 | return requestUrl
|
37 | }
|
38 | }
|
39 |
|
40 | function parseHeaders (headers) {
|
41 | var object = {}
|
42 | var lines = headers.split('\n')
|
43 |
|
44 | for (var n = 0; n < lines.length; n++) {
|
45 | var line = lines[n]
|
46 | var match = /^(.*?):(.*)/.exec(line)
|
47 |
|
48 | if (match) {
|
49 | object[match[1].toLowerCase()] = match[2].trim()
|
50 | }
|
51 | }
|
52 |
|
53 | return object
|
54 | }
|
55 |
|
56 | function addAbortToPromise (promise, abort) {
|
57 | var then = promise.then
|
58 | promise.then = function () {
|
59 | var p = then.apply(this, arguments)
|
60 | p.abort = abort
|
61 | addAbortToPromise(p, abort)
|
62 | return p
|
63 | }
|
64 | }
|
65 |
|
66 | module.exports = middleware('xhr', function (request) {
|
67 | var Xhr = request.options.xhr || window.XMLHttpRequest
|
68 | var xhr = new Xhr()
|
69 | var rejectPromise
|
70 |
|
71 | var promise = new Promise(function (resolve, reject) {
|
72 | rejectPromise = reject
|
73 | xhr.open(request.method, request.url, true)
|
74 | xhr.onload = function () {
|
75 | var statusCode = xhr.status
|
76 |
|
77 | var response = {
|
78 | body: statusCode === 204 ? undefined : xhr.responseText,
|
79 | headers: parseHeaders(xhr.getAllResponseHeaders()),
|
80 | statusCode: statusCode,
|
81 | url: responseUrl(xhr, request.url),
|
82 | xhr: xhr,
|
83 | statusText: xhr.statusText
|
84 | }
|
85 |
|
86 | resolve(response)
|
87 | }
|
88 |
|
89 | xhr.onerror = function () {
|
90 | rejectPromise(new Error('failed to connect to ' + request.method + ' ' + request.url))
|
91 | }
|
92 |
|
93 | if (!isCrossDomain(request.url) && !request.headers['x-requested-with']) {
|
94 | request.headers['x-requested-with'] = 'XMLHttpRequest'
|
95 | }
|
96 |
|
97 | setHeaders(request.headers, xhr)
|
98 | xhr.withCredentials = !!request.options.withCredentials
|
99 |
|
100 | xhr.send(request.body)
|
101 | })
|
102 |
|
103 | function abort () {
|
104 | xhr.abort()
|
105 | var error = new Error('aborted connection to ' + request.method + ' ' + request.url)
|
106 | error.aborted = true
|
107 | rejectPromise(error)
|
108 | }
|
109 | addAbortToPromise(promise, abort)
|
110 |
|
111 | return promise
|
112 | })
|