-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathhttp.js
More file actions
162 lines (148 loc) · 5.71 KB
/
http.js
File metadata and controls
162 lines (148 loc) · 5.71 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
const isBrowser=new Function("try {return this===window;}catch(e){ return false;}")();
console.log(isBrowser ? `detected browser` : `detected node`);
// fill in missing global dependencies
if(isBrowser) {
// window.Buffer so stellar-base stuff works in the browser
await import('buffer').then(mod => window.Buffer = mod.Buffer);
}
else {
var [Blob, Buffer, https, http] = await Promise.all([import('buffer'), import('https'), import('http')])
.then(([bufMod, https, http]) => [bufMod.Blob, bufMod.Buffer, https, http]);
await import('eventsource').then((EventSource) => global.EventSource = EventSource.default);
await import('ws').then(WS => global.WebSocket = WS.default);
global.localStorage = {
setItem: function(key, value){
this[key] = value
},
getItem: function(key){return this[key]},
removeItem: function(key){delete this.key}
};
}
//remove these
//console.log(`http is `, http);
//console.log(`https is `, https);
//console.log(`still interpreting http.js`);
// concattenate lines of multifunction form data request body
function abConcat(arrays){
let length = arrays.reduce((acc, value) => acc + value.length, 0);
let result = new Uint8Array(length);
if (!arrays.length) return result;
// for each array - copy it over result
// next array is copied right after the previous one
length = 0;
for(let array of arrays) {
result.set(array, length);
length += array.length;
}
return result;
}
function mfdTextSegment(text){
const bytes = new TextEncoder().encode(text);
//console.log(`created TextEncoder of ${text}: `, bytes);
if(bytes.length !== text.length)
throw new Error(`Unexpected Unicode found in multipart/form-data text`)
return bytes
}
//
export function mfdOpts(fileIshes, options={}){
// filishes must be itterable
const segments = [];
const boundary = `-----------------XYZ${Date.now()}ABC`;
const startOfPart = mfdTextSegment(`--${boundary}\r\n`);
for(let fileIsh of fileIshes){
const fileName = typeof fileIsh.name === 'string' && fileIsh.name.length > 0 ? ` filename="${fileIsh.name}"\r\n`: `\r\n`;
segments.push(startOfPart);
segments.push(mfdTextSegment(`Content-Disposition: form-data; name="file";${fileName}`));
segments.push(mfdTextSegment(`Content-Type: ${fileIsh.type}\r\n\r\n`));
segments.push(fileIsh.data);
segments.push(mfdTextSegment('\r\n'));
}
segments.push(mfdTextSegment(`--${boundary}--`));
if(Object.hasOwn(options, 'headers'))
options.headers['Content-Type'] = `multipart/form-data; boundary=${boundary}`;
else
options.headers = {'Content-Type': `multipart/form-data; boundary=${boundary}`};
options['body'] = abConcat(segments);
return options
}
// https request over XMLHttpRequest or node.https
export function request(url, options={}, logArray=[]){
return new Promise(function(resolve, reject){
if(logArray.length > 0)
logArray[new Date().toISOString()] = `request to ${url.slice(0, url.indexOf('?'))}`;
if(isBrowser){
const req = new XMLHttpRequest();
req.onreadystatechange = function (e) {
if(req.readyState === XMLHttpRequest.DONE){
var status = req.status;
if(status === 0 || (status >= 200 && status < 400)){
if(logArray.length > 0)
logArray[new Date().toISOString()] = `request.status = ${status}`;
resolve(req.response);
}
else {
if(logArray.length > 0)
logArray[new Date().toISOString()] = `request.status = ${status}`;
console.error(`XMLHttpRequest unexpected termination status: ${status}`)
reject(req.response);
}
}
};
req.addEventListener('error', e => console.error(`XMLHttpRequest produced error: `, e));
if(options.hasOwnProperty('method') && options.method.toUpperCase() === 'POST')
req.open('POST', url);
else
req.open('GET', url);
if(options?.headers)
for(let key of Object.keys(options.headers)){
req.setRequestHeader(key, options.headers[key]);
if(key === 'Accept' && options.headers[key] === "application/vnd.ipld.raw")
req.responseType = "arraybuffer";
}
if(options?.body){
req.send(options.body);
}
else{
req.send();
}
}
else { // before use this needs to condition options for post
const protocol = url.split(':')[0] === 'http' ? http : https;
const req = protocol.request(url, options, (response) => {
let data;
if(options?.headers && 'Accept' in options.headers && options.headers.Accept === 'application/vnd.ipld.raw'){
data = new Uint8Array();
response.on('data', (chunk) => {
data = abConcat([data, chunk]);
});
} else {
data = '';
response.on('data', (chunk) => {
data = data + chunk.toString();
});
}
response.on('end', () => {
if(logArray.length > 0)
logArray[new Date().toISOString()] = `request.status = ${'completed'}`;
resolve(data);
});
response.on('error', (error) => {
if(logArray.length > 0)
logArray[new Date().toISOString()] = `request.status = ${error.message}`;
console.error('An http error', error);
reject(error);
});
});
req.on('error', (error) => {
if(logArray.length > 0)
logArray[new Date().toISOString()] = `request.status = ${error.message}`;
console.error('An http error', error);
reject(error);
});
if(options.hasOwnProperty('method') && options.method.toUpperCase() === 'POST')
req.end(options?.body);
else
req.end();
}
})
}