Software zum Installieren eines Smart-Mirror Frameworks , zum Nutzen von hochschulrelevanten Informationen, auf einem Raspberry-Pi.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

README.md 13KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470
  1. # http2-wrapper
  2. > HTTP/2 client, just with the familiar `https` API
  3. [![Node CI](https://github.com/szmarczak/http2-wrapper/workflows/Node%20CI/badge.svg)](https://github.com/szmarczak/http2-wrapper/actions)
  4. [![codecov](https://codecov.io/gh/szmarczak/http2-wrapper/branch/master/graph/badge.svg)](https://codecov.io/gh/szmarczak/http2-wrapper)
  5. [![npm](https://img.shields.io/npm/dm/http2-wrapper.svg)](https://www.npmjs.com/package/http2-wrapper)
  6. [![install size](https://packagephobia.now.sh/badge?p=http2-wrapper)](https://packagephobia.now.sh/result?p=http2-wrapper)
  7. This package was created to support HTTP/2 without the need to rewrite your code.<br>
  8. I recommend adapting to the [`http2`](https://nodejs.org/api/http2.html) module if possible - it's much simpler to use and has many cool features!
  9. **Tip**: `http2-wrapper` is very useful when you rely on other modules that use the HTTP/1 API and you want to support HTTP/2.
  10. **Pro Tip**: While the native `http2` doesn't have agents yet, you can use `http2-wrapper` Agents and still operate on the native HTTP/2 streams.
  11. ## Installation
  12. > `$ npm install http2-wrapper`<br>
  13. > `$ yarn add http2-wrapper`
  14. ## Usage
  15. ```js
  16. const http2 = require('http2-wrapper');
  17. const options = {
  18. hostname: 'nghttp2.org',
  19. protocol: 'https:',
  20. path: '/httpbin/post',
  21. method: 'POST',
  22. headers: {
  23. 'content-length': 6
  24. }
  25. };
  26. const request = http2.request(options, response => {
  27. console.log('statusCode:', response.statusCode);
  28. console.log('headers:', response.headers);
  29. const body = [];
  30. response.on('data', chunk => {
  31. body.push(chunk);
  32. });
  33. response.on('end', () => {
  34. console.log('body:', Buffer.concat(body).toString());
  35. });
  36. });
  37. request.on('error', console.error);
  38. request.write('123');
  39. request.end('456');
  40. // statusCode: 200
  41. // headers: [Object: null prototype] {
  42. // ':status': 200,
  43. // date: 'Fri, 27 Sep 2019 19:45:46 GMT',
  44. // 'content-type': 'application/json',
  45. // 'access-control-allow-origin': '*',
  46. // 'access-control-allow-credentials': 'true',
  47. // 'content-length': '239',
  48. // 'x-backend-header-rtt': '0.002516',
  49. // 'strict-transport-security': 'max-age=31536000',
  50. // server: 'nghttpx',
  51. // via: '1.1 nghttpx',
  52. // 'alt-svc': 'h3-23=":4433"; ma=3600',
  53. // 'x-frame-options': 'SAMEORIGIN',
  54. // 'x-xss-protection': '1; mode=block',
  55. // 'x-content-type-options': 'nosniff'
  56. // }
  57. // body: {
  58. // "args": {},
  59. // "data": "123456",
  60. // "files": {},
  61. // "form": {},
  62. // "headers": {
  63. // "Content-Length": "6",
  64. // "Host": "nghttp2.org"
  65. // },
  66. // "json": 123456,
  67. // "origin": "xxx.xxx.xxx.xxx",
  68. // "url": "https://nghttp2.org/httpbin/post"
  69. // }
  70. ```
  71. ## API
  72. **Note:** The `session` option was renamed to `tlsSession` for better readability.
  73. ### http2.auto(url, options, callback)
  74. Performs [ALPN](https://nodejs.org/api/tls.html#tls_alpn_and_sni) negotiation.
  75. Returns a Promise giving proper `ClientRequest` instance (depending on the ALPN).
  76. **Note**: The `agent` option represents an object with `http`, `https` and `http2` properties.
  77. ```js
  78. const http2 = require('http2-wrapper');
  79. const options = {
  80. hostname: 'httpbin.org',
  81. protocol: 'http:', // Note the `http:` protocol here
  82. path: '/post',
  83. method: 'POST',
  84. headers: {
  85. 'content-length': 6
  86. }
  87. };
  88. (async () => {
  89. try {
  90. const request = await http2.auto(options, response => {
  91. console.log('statusCode:', response.statusCode);
  92. console.log('headers:', response.headers);
  93. const body = [];
  94. response.on('data', chunk => body.push(chunk));
  95. response.on('end', () => {
  96. console.log('body:', Buffer.concat(body).toString());
  97. });
  98. });
  99. request.on('error', console.error);
  100. request.write('123');
  101. request.end('456');
  102. } catch (error) {
  103. console.error(error);
  104. }
  105. })();
  106. // statusCode: 200
  107. // headers: { connection: 'close',
  108. // server: 'gunicorn/19.9.0',
  109. // date: 'Sat, 15 Dec 2018 18:19:32 GMT',
  110. // 'content-type': 'application/json',
  111. // 'content-length': '259',
  112. // 'access-control-allow-origin': '*',
  113. // 'access-control-allow-credentials': 'true',
  114. // via: '1.1 vegur' }
  115. // body: {
  116. // "args": {},
  117. // "data": "123456",
  118. // "files": {},
  119. // "form": {},
  120. // "headers": {
  121. // "Connection": "close",
  122. // "Content-Length": "6",
  123. // "Host": "httpbin.org"
  124. // },
  125. // "json": 123456,
  126. // "origin": "xxx.xxx.xxx.xxx",
  127. // "url": "http://httpbin.org/post"
  128. // }
  129. ```
  130. ### http2.auto.protocolCache
  131. An instance of [`quick-lru`](https://github.com/sindresorhus/quick-lru) used for ALPN cache.
  132. There is a maximum of 100 entries. You can modify the limit through `protocolCache.maxSize` - note that the change will be visible globally.
  133. ### http2.request(url, options, callback)
  134. Same as [`https.request`](https://nodejs.org/api/https.html#https_https_request_options_callback).
  135. ##### options.h2session
  136. Type: `Http2Session`<br>
  137. The session used to make the actual request. If none provided, it will use `options.agent`.
  138. ### http2.get(url, options, callback)
  139. Same as [`https.get`](https://nodejs.org/api/https.html#https_https_get_options_callback).
  140. ### new http2.ClientRequest(url, options, callback)
  141. Same as [`https.ClientRequest`](https://nodejs.org/api/https.html#https_class_https_clientrequest).
  142. ### new http2.IncomingMessage(socket)
  143. Same as [`https.IncomingMessage`](https://nodejs.org/api/https.html#https_class_https_incomingmessage).
  144. ### new http2.Agent(options)
  145. **Note:** this is **not** compatible with the classic `http.Agent`.
  146. Usage example:
  147. ```js
  148. const http2 = require('http2-wrapper');
  149. class MyAgent extends http2.Agent {
  150. createConnection(origin, options) {
  151. console.log(`Connecting to ${http2.Agent.normalizeOrigin(origin)}`);
  152. return http2.Agent.connect(origin, options);
  153. }
  154. }
  155. http2.get({
  156. hostname: 'google.com',
  157. agent: new MyAgent()
  158. }, res => {
  159. res.on('data', chunk => console.log(`Received chunk of ${chunk.length} bytes`));
  160. });
  161. ```
  162. #### options
  163. Each option is assigned to each `Agent` instance and can be changed later.
  164. ##### timeout
  165. Type: `number`<br>
  166. Default: `60000`
  167. If there's no activity after `timeout` milliseconds, the session will be closed.
  168. ##### maxSessions
  169. Type: `number`<br>
  170. Default: `Infinity`
  171. The maximum amount of sessions in total.
  172. ##### maxFreeSessions
  173. Type: `number`<br>
  174. Default: `10`
  175. The maximum amount of free sessions in total. This only applies to sessions with no pending requests.
  176. **Note:** It is possible that the amount will be exceeded when sessions have at least 1 pending request.
  177. ##### maxCachedTlsSessions
  178. Type: `number`<br>
  179. Default: `100`
  180. The maximum amount of cached TLS sessions.
  181. #### Agent.normalizeOrigin(url)
  182. Returns a string representing the origin of the URL.
  183. #### agent.settings
  184. Type: `object`<br>
  185. Default: `{enablePush: false}`
  186. [Settings](https://nodejs.org/api/http2.html#http2_settings_object) used by the current agent instance.
  187. #### agent.normalizeOptions([options](https://github.com/szmarczak/http2-wrapper/blob/master/source/agent.js))
  188. Returns a string representing normalized options.
  189. ```js
  190. Agent.normalizeOptions({servername: 'example.com'});
  191. // => ':example.com'
  192. ```
  193. #### agent.getSession(origin, options)
  194. ##### [origin](https://nodejs.org/api/http2.html#http2_http2_connect_authority_options_listener)
  195. Type: `string` `URL` `object`
  196. An origin used to create new session.
  197. ##### [options](https://nodejs.org/api/http2.html#http2_http2_connect_authority_options_listener)
  198. Type: `object`
  199. The options used to create new session.
  200. Returns a Promise giving free `Http2Session`. If no free sessions are found, a new one is created.
  201. #### agent.getSession([origin](#origin), [options](options-1), listener)
  202. ##### listener
  203. Type: `object`
  204. ```
  205. {
  206. reject: error => void,
  207. resolve: session => void
  208. }
  209. ```
  210. If the `listener` argument is present, the Promise will resolve immediately. It will use the `resolve` function to pass the session.
  211. #### agent.request([origin](#origin), [options](#options-1), [headers](https://nodejs.org/api/http2.html#http2_headers_object), [streamOptions](https://nodejs.org/api/http2.html#http2_clienthttp2session_request_headers_options))
  212. Returns a Promise giving `Http2Stream`.
  213. #### agent.createConnection([origin](#origin), [options](#options-1))
  214. Returns a new `TLSSocket`. It defaults to `Agent.connect(origin, options)`.
  215. #### agent.closeFreeSessions()
  216. Makes an attempt to close free sessions. Only sessions with 0 concurrent streams will be closed.
  217. #### agent.destroy(reason)
  218. Destroys **all** sessions.
  219. #### Event: 'session'
  220. ```js
  221. agent.on('session', session => {
  222. // A new session has been created by the Agent.
  223. });
  224. ```
  225. ## Proxy support
  226. An example of a full-featured proxy server can be found [here](examples/proxy/server.js). It supports **mirroring, custom authorities and the CONNECT protocol**.
  227. ### Mirroring
  228. To mirror another server we need to use only [`http2-proxy`](https://github.com/nxtedition/node-http2-proxy). We don't need the CONNECT protocol or custom authorities.
  229. To see the result, just navigate to the server's address.
  230. ### HTTP/1 over HTTP/2
  231. Since we don't care about mirroring, the server needs to support the CONNECT protocol in this case.
  232. The client looks like this:
  233. ```js
  234. const https = require('https');
  235. const http2 = require('http2');
  236. const session = http2.connect('https://localhost:8000', {
  237. // For demo purposes only!
  238. rejectUnauthorized: false
  239. });
  240. session.ref();
  241. https.request('https://httpbin.org/anything', {
  242. createConnection: options => {
  243. return session.request({
  244. ':method': 'CONNECT',
  245. ':authority': `${options.host}:${options.port}`
  246. });
  247. }
  248. }, response => {
  249. console.log('statusCode:', response.statusCode);
  250. console.log('headers:', response.headers);
  251. const body = [];
  252. response.on('data', chunk => {
  253. body.push(chunk);
  254. });
  255. response.on('end', () => {
  256. console.log('body:', Buffer.concat(body).toString());
  257. session.unref();
  258. });
  259. }).end();
  260. ```
  261. ### HTTP/2 over HTTP/2
  262. It's a tricky one! We cannot create an HTTP/2 session on top of an HTTP/2 stream. But... we can still specify the `:authority` header, no need to use the CONNECT protocol here.
  263. The client looks like this:
  264. ```js
  265. const http2 = require('../../source');
  266. const {Agent} = http2;
  267. class ProxyAgent extends Agent {
  268. constructor(url, options) {
  269. super(options);
  270. this.origin = url;
  271. }
  272. request(origin, sessionOptions, headers, streamOptions) {
  273. return super.request(this.origin, sessionOptions, {
  274. ...headers,
  275. ':authority': (new URL(origin)).host
  276. }, streamOptions);
  277. }
  278. }
  279. const request = http2.request({
  280. hostname: 'httpbin.org',
  281. protocol: 'https:',
  282. path: '/anything',
  283. agent: new ProxyAgent('https://localhost:8000'),
  284. // For demo purposes only!
  285. rejectUnauthorized: false
  286. }, response => {
  287. console.log('statusCode:', response.statusCode);
  288. console.log('headers:', response.headers);
  289. const body = [];
  290. response.on('data', chunk => {
  291. body.push(chunk);
  292. });
  293. response.on('end', () => {
  294. console.log('body:', Buffer.concat(body).toString());
  295. });
  296. });
  297. request.on('error', console.error);
  298. request.end();
  299. ```
  300. ## Notes
  301. - If you're interested in [WebSockets over HTTP/2](https://tools.ietf.org/html/rfc8441), then [check out this discussion](https://github.com/websockets/ws/issues/1458).
  302. - [HTTP/2 sockets cannot be malformed](https://github.com/nodejs/node/blob/cc8250fab86486632fdeb63892be735d7628cd13/lib/internal/http2/core.js#L725), therefore modifying the socket will have no effect.
  303. - You can make [a custom Agent](examples/push-stream/index.js) to support push streams.
  304. ## Benchmarks
  305. CPU: Intel i7-7700k (governor: performance)<br>
  306. Server: H2O v2.2.5 [`h2o.conf`](h2o.conf)<br>
  307. Node: v14.5.0
  308. Linux: 5.6.18-156.current
  309. `auto` means `http2wrapper.auto`.
  310. ```
  311. http2-wrapper x 12,181 ops/sec ±3.39% (75 runs sampled)
  312. http2-wrapper - preconfigured session x 13,140 ops/sec ±2.51% (79 runs sampled)
  313. http2-wrapper - auto x 11,412 ops/sec ±2.55% (78 runs sampled)
  314. http2 x 16,050 ops/sec ±1.39% (86 runs sampled)
  315. https - auto - keepalive x 12,288 ops/sec ±2.69% (79 runs sampled)
  316. https - keepalive x 12,155 ops/sec ±3.32% (78 runs sampled)
  317. https x 1,604 ops/sec ±2.03% (77 runs sampled)
  318. http x 6,041 ops/sec ±3.82% (76 runs sampled)
  319. Fastest is http2
  320. ```
  321. `http2-wrapper`:
  322. - 32% **less** performant than `http2`
  323. - as performant as `https - keepalive`
  324. - 100% **more** performant than `http`
  325. `http2-wrapper - preconfigured session`:
  326. - 22% **less** performant than `http2`
  327. - 8% **more** performant than `https - keepalive`
  328. - 118% **more** performant than `http`
  329. `http2-wrapper - auto`:
  330. - 41% **less** performant than `http2`
  331. - 8% **less** performant than `https - keepalive`
  332. - 89% **more** performant than `http`
  333. `https - auto - keepalive`:
  334. - 31% **less** performant than `http2`
  335. - as performant as `https - keepalive`
  336. - 103% **more** performant than `http`
  337. ## Related
  338. - [`got`](https://github.com/sindresorhus/got) - Simplified HTTP requests
  339. ## License
  340. MIT