/
http-client.js
165 lines (144 loc) · 4.55 KB
/
http-client.js
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
163
164
165
// -- isaacs Isaac Schleuter TODO
// -- airportyh TODO
// -- kriskowal Kris Kowal Copyright (C) 2009-2010 MIT License
// -- cadorn Christoph Dorn TODO
var IO = require("io").IO,
UTIL = require("util"),
ENGINE = require("http-client-engine");
exports.open = function (url, mode, options) {
// todo mode negotiation, particularly for binary vs text buffering
return new ENGINE.IO(url);
};
exports.read = function (url) {
var stream = exports.open(url);
try {
return stream.read();
} finally {
stream.close();
}
};
exports.HttpClient = HttpClient;
var newTransactionId = (function () {
var id = 1;
return function () {
return id ++;
};
})();
var transaction = (function () {
var hidden = {};
return function (id, del) {
if (del && hidden.hasOwnProperty(id)) {
delete hidden[id];
return;
}
if (!hidden.hasOwnProperty(id)) hidden[id] = {};
return hidden[id];
};
})();
// {method, url, headers, body}
// return value is {status:status, headers:{..}, body:[..]}
function HttpClient (settings) {
if (!(this instanceof HttpClient)) return new HttpClient(settings);
if (!this.txId) this.create();
if (settings) this.setOptions(settings);
};
HttpClient.prototype = {
create : function HttpClient_create () {
// clean up, set up defaults.
transaction(this.txId, true);
this.txId = newTransactionId();
this.setOptions({
"method" : "GET",
"headers" : {},
"body" : []
});
return this;
},
setOptions : function HttpClient_setOption (settings) {
for (var key in settings) if (settings.hasOwnProperty(key)) {
this.setOption(key, settings[key]);
}
return this;
},
setOption : function HttpClient_setOption (key, val) {
var guts = transaction(this.txId);
switch (key) {
case "headers":
if (typeof val !== 'object') throw new Error(
"HttpClient: headers must be a simple object."
);
return this.setHeaders(val);
case "body":
if (typeof val.forEach !== 'function') throw new Error(
"HttpClient: body must be iterable."
);
// fallthrough
default:
guts[key] = val;
}
return this;
},
setHeaders : function HttpClient_setHeaders (headers) {
for (var h in headers) if (headers.hasOwnProperty(h)) {
this.setHeader(h, headers[h]);
}
return this;
},
setHeader : function HttpClient_setHeader (key, val) {
var guts = transaction(this.txId);
if (!guts.hasOwnProperty("headers")) guts.headers = {};
UTIL.set(guts.headers, key, val);
return this;
},
write : function HttpClient_write (data) {
var guts = transaction(this.txId);
var len = UTIL.get(guts.headers, "Content-Length") || 0;
len += data.length;
UTIL.set(guts.headers, "Content-Length", len);
guts.body.push(data);
return this;
},
connect : function HttpClient_connect (decode) {
var guts = transaction(this.txId);
var resp = ENGINE.connect(guts);
if (decode) HttpClient.decode(resp);
transaction(this.txId, true);
return resp;
}
};
HttpClient.decode = function HttpClient_decode (resp, encoding) {
encoding = encoding || UTIL.get(resp.headers, "Content-Encoding");
if (!encoding) {
var contentType = UTIL.get(resp.headers, "Content-Type");
if (contentType) {
encoding = /charset=([^;\s]+)/.exec(contentType);
if (encoding) encoding = encoding[1];
}
}
// fall back on UTF-8. It's almost always a good choice.
if (!encoding) encoding = 'UTF-8';
var raw = resp.body;
resp._rawBody = raw;
resp.body = {forEach : function (block) {
raw.forEach(function (i) {
block(i.decodeToString(encoding));
});
}};
return resp;
};
HttpClient.undecode = function HttpClient_undecode (resp) {
if ("_rawBody" in resp) resp.body = resp._rawBody;
delete resp._rawBody;
return resp;
};
HttpClient.print = function HttpClient_print (resp) {
var out = [];
out.push(resp.statusText);
UTIL.forEach(resp.headers, function (h, v) {
out.push(h+": "+v);
});
out.push("");
out=[out.join("\n")];
resp.body.forEach(function (p) { out.push(p) });
print(out.join(""));
};