Skip to content
Permalink

Comparing changes

This is a direct comparison between two commits made in this repository or its related repositories. View the default comparison for this range or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: nodejs/node
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: 4bb72eb4eecbe711cd3d91683c425600a8d67286
Choose a base ref
..
head repository: nodejs/node
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: ede6c54f5789c43d6001870923acf8d3b6e6cee8
Choose a head ref
Showing with 316 additions and 14 deletions.
  1. +314 −12 doc/api/http.md
  2. +1 −1 doc/api/policy.md
  3. +1 −1 src/node_version.h
326 changes: 314 additions & 12 deletions doc/api/http.md
Original file line number Diff line number Diff line change
@@ -187,7 +187,14 @@ of these values set to their respective defaults.

To configure any of them, a custom [`http.Agent`][] instance must be created.

```js
```mjs
import { Agent, request } from 'node:http';
const keepAliveAgent = new Agent({ keepAlive: true });
options.agent = keepAliveAgent;
request(options, onResponseCallback);
```

```cjs
const http = require('node:http');
const keepAliveAgent = new http.Agent({ keepAlive: true });
options.agent = keepAliveAgent;
@@ -474,7 +481,62 @@ type other than {net.Socket}.

A client and server pair demonstrating how to listen for the `'connect'` event:

```js
```mjs
import { createServer, request } from 'node:http';
import { connect } from 'node:net';
import { URL } from 'node:url';

// Create an HTTP tunneling proxy
const proxy = createServer((req, res) => {
res.writeHead(200, { 'Content-Type': 'text/plain' });
res.end('okay');
});
proxy.on('connect', (req, clientSocket, head) => {
// Connect to an origin server
const { port, hostname } = new URL(`http://${req.url}`);
const serverSocket = connect(port || 80, hostname, () => {
clientSocket.write('HTTP/1.1 200 Connection Established\r\n' +
'Proxy-agent: Node.js-Proxy\r\n' +
'\r\n');
serverSocket.write(head);
serverSocket.pipe(clientSocket);
clientSocket.pipe(serverSocket);
});
});

// Now that proxy is running
proxy.listen(1337, '127.0.0.1', () => {

// Make a request to a tunneling proxy
const options = {
port: 1337,
host: '127.0.0.1',
method: 'CONNECT',
path: 'www.google.com:80',
};

const req = request(options);
req.end();

req.on('connect', (res, socket, head) => {
console.log('got connected!');

// Make a request over an HTTP tunnel
socket.write('GET / HTTP/1.1\r\n' +
'Host: www.google.com:80\r\n' +
'Connection: close\r\n' +
'\r\n');
socket.on('data', (chunk) => {
console.log(chunk.toString());
});
socket.on('end', () => {
proxy.close();
});
});
});
```

```cjs
const http = require('node:http');
const net = require('node:net');
const { URL } = require('node:url');
@@ -570,7 +632,25 @@ Upgrade). The listeners of this event will receive an object containing the
HTTP version, status code, status message, key-value headers object,
and array with the raw header names followed by their respective values.

```js
```mjs
import { request } from 'node:http';

const options = {
host: '127.0.0.1',
port: 8080,
path: '/length_request',
};

// Make a request
const req = request(options);
req.end();

req.on('information', (info) => {
console.log(`Got information prior to main response: ${info.statusCode}`);
});
```

```cjs
const http = require('node:http');

const options = {
@@ -648,7 +728,49 @@ type other than {net.Socket}.

A client server pair demonstrating how to listen for the `'upgrade'` event.

```js
```mjs
import http from 'node:http';
import process from 'node:process';

// Create an HTTP server
const server = http.createServer((req, res) => {
res.writeHead(200, { 'Content-Type': 'text/plain' });
res.end('okay');
});
server.on('upgrade', (req, socket, head) => {
socket.write('HTTP/1.1 101 Web Socket Protocol Handshake\r\n' +
'Upgrade: WebSocket\r\n' +
'Connection: Upgrade\r\n' +
'\r\n');

socket.pipe(socket); // echo back
});

// Now that server is running
server.listen(1337, '127.0.0.1', () => {

// make a request
const options = {
port: 1337,
host: '127.0.0.1',
headers: {
'Connection': 'Upgrade',
'Upgrade': 'websocket',
},
};

const req = http.request(options);
req.end();

req.on('upgrade', (res, socket, upgradeHead) => {
console.log('got upgraded!');
socket.end();
process.exit(0);
});
});
```

```cjs
const http = require('node:http');

// Create an HTTP server
@@ -1019,7 +1141,28 @@ When sending request through a keep-alive enabled agent, the underlying socket
might be reused. But if server closes connection at unfortunate time, client
may run into a 'ECONNRESET' error.

```js
```mjs
import http from 'node:http';

// Server has a 5 seconds keep-alive timeout by default
http
.createServer((req, res) => {
res.write('hello\n');
res.end();
})
.listen(3000);

setInterval(() => {
// Adapting a keep-alive agent
http.get('http://localhost:3000', { agent }, (res) => {
res.on('data', (data) => {
// Do nothing
});
});
}, 5000); // Sending request on 5s interval so it's easy to hit idle timeout
```

```cjs
const http = require('node:http');

// Server has a 5 seconds keep-alive timeout by default
@@ -1043,7 +1186,27 @@ setInterval(() => {
By marking a request whether it reused socket or not, we can do
automatic error retry base on it.

```js
```mjs
import http from 'node:http';
const agent = new http.Agent({ keepAlive: true });

function retriableRequest() {
const req = http
.get('http://localhost:3000', { agent }, (res) => {
// ...
})
.on('error', (err) => {
// Check if retry is needed
if (req.reusedSocket && err.code === 'ECONNRESET') {
retriableRequest();
}
});
}

retriableRequest();
```

```cjs
const http = require('node:http');
const agent = new http.Agent({ keepAlive: true });

@@ -1153,7 +1316,22 @@ Reference to the underlying socket. Usually users will not want to access
this property. In particular, the socket will not emit `'readable'` events
because of how the protocol parser attaches to the socket.

```js
```mjs
import http from 'node:http';
const options = {
host: 'www.google.com',
};
const req = http.get(options);
req.end();
req.once('response', (res) => {
const ip = req.socket.localAddress;
const port = req.socket.localPort;
console.log(`Your IP address is ${ip} and your source port is ${port}.`);
// Consume response object
});
```

```cjs
const http = require('node:http');
const options = {
host: 'www.google.com',
@@ -1326,7 +1504,19 @@ immediately destroyed.

`socket` is the [`net.Socket`][] object that the error originated from.

```js
```mjs
import http from 'node:http';

const server = http.createServer((req, res) => {
res.end();
});
server.on('clientError', (err, socket) => {
socket.end('HTTP/1.1 400 Bad Request\r\n\r\n');
});
server.listen(8000);
```

```cjs
const http = require('node:http');

const server = http.createServer((req, res) => {
@@ -2034,7 +2224,16 @@ this property. In particular, the socket will not emit `'readable'` events
because of how the protocol parser attaches to the socket. After
`response.end()`, the property is nulled.

```js
```mjs
import http from 'node:http';
const server = http.createServer((req, res) => {
const ip = res.socket.remoteAddress;
const port = res.socket.remotePort;
res.end(`Your IP address is ${ip} and your source port is ${port}.`);
}).listen(3000);
```

```cjs
const http = require('node:http');
const server = http.createServer((req, res) => {
const ip = res.socket.remoteAddress;
@@ -3306,6 +3505,20 @@ Returns a new instance of [`http.Server`][].
The `requestListener` is a function which is automatically
added to the [`'request'`][] event.

```mjs
import http from 'node:http';

// Create a local server to receive data from
const server = http.createServer((req, res) => {
res.writeHead(200, { 'Content-Type': 'application/json' });
res.end(JSON.stringify({
data: 'Hello World!',
}));
});

server.listen(8000);
```

```cjs
const http = require('node:http');

@@ -3320,6 +3533,23 @@ const server = http.createServer((req, res) => {
server.listen(8000);
```

```mjs
import http from 'node:http';

// Create a local server to receive data from
const server = http.createServer();

// Listen to the request event
server.on('request', (request, res) => {
res.writeHead(200, { 'Content-Type': 'application/json' });
res.end(JSON.stringify({
data: 'Hello World!',
}));
});

server.listen(8000);
```

```cjs
const http = require('node:http');

@@ -3569,7 +3799,47 @@ the [`'response'`][] event.
class. The `ClientRequest` instance is a writable stream. If one needs to
upload a file with a POST request, then write to the `ClientRequest` object.

```js
```mjs
import http from 'node:http';
import { Buffer } from 'node:buffer';

const postData = JSON.stringify({
'msg': 'Hello World!',
});

const options = {
hostname: 'www.google.com',
port: 80,
path: '/upload',
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Content-Length': Buffer.byteLength(postData),
},
};

const req = http.request(options, (res) => {
console.log(`STATUS: ${res.statusCode}`);
console.log(`HEADERS: ${JSON.stringify(res.headers)}`);
res.setEncoding('utf8');
res.on('data', (chunk) => {
console.log(`BODY: ${chunk}`);
});
res.on('end', () => {
console.log('No more data in response.');
});
});

req.on('error', (e) => {
console.error(`problem with request: ${e.message}`);
});

// Write data to request body
req.write(postData);
req.end();
```

```cjs
const http = require('node:http');

const postData = JSON.stringify({
@@ -3777,7 +4047,19 @@ Examples:

Example:

```js
```mjs
import { validateHeaderName } from 'node:http';

try {
validateHeaderName('');
} catch (err) {
console.error(err instanceof TypeError); // --> true
console.error(err.code); // --> 'ERR_INVALID_HTTP_TOKEN'
console.error(err.message); // --> 'Header name must be a valid HTTP token [""]'
}
```

```cjs
const { validateHeaderName } = require('node:http');

try {
@@ -3811,7 +4093,27 @@ or response. The HTTP module will automatically validate such headers.

Examples:

```js
```mjs
import { validateHeaderValue } from 'node:http';

try {
validateHeaderValue('x-my-header', undefined);
} catch (err) {
console.error(err instanceof TypeError); // --> true
console.error(err.code === 'ERR_HTTP_INVALID_HEADER_VALUE'); // --> true
console.error(err.message); // --> 'Invalid value "undefined" for header "x-my-header"'
}

try {
validateHeaderValue('x-my-header', 'oʊmɪɡə');
} catch (err) {
console.error(err instanceof TypeError); // --> true
console.error(err.code === 'ERR_INVALID_CHAR'); // --> true
console.error(err.message); // --> 'Invalid character in header content ["x-my-header"]'
}
```

```cjs
const { validateHeaderValue } = require('node:http');

try {
2 changes: 1 addition & 1 deletion doc/api/policy.md
Original file line number Diff line number Diff line change
@@ -6,6 +6,6 @@

> Stability: 1 - Experimental
The former Policies documentation is now at [Permissions documentation][]
The former Policies documentation is now at [Permissions documentation][].

[Permissions documentation]: permissions.md#policies
2 changes: 1 addition & 1 deletion src/node_version.h
Original file line number Diff line number Diff line change
@@ -29,7 +29,7 @@
#define NODE_VERSION_IS_LTS 0
#define NODE_VERSION_LTS_CODENAME ""

#define NODE_VERSION_IS_RELEASE 1
#define NODE_VERSION_IS_RELEASE 0

#ifndef NODE_STRINGIFY
#define NODE_STRINGIFY(n) NODE_STRINGIFY_HELPER(n)