WebHTTPHTTP

WebHTTP fetch()
Gyazo

HTTP

<input type="file"> FileBlobHTTP
HTTP
E2E

HTTP
WebWebSocketWebRTCWeb使


HTTP
HTTP
nctelnetHTTP/1.1

HTTP使iOSShortchutMicrosoft FlowDocker/var/run/docker.sock WebHTTP使HTTP

HTTP/1.1
TCP使HTTP/2
UDPQUIC使HTTP/3
HTTP
HTTP/3QUICIP

WebWebHTTP

javascript
fetch(myUrl, {
method: 'POST',
body: <ReadableStream>
})
fetch body: ReadableStream 使
調XMLHttpRequestPolyfillWebSocket使HTTP

fetch()
fetch() 使HTTPHTTPaxios fetch() 使使Web XMLHttpRequest API

ReadableStream
使
javascript
//
new ReadableStream({
pull(ctrl) {
ctrl.enqueue(window.crypto.getRandomValues(new Uint32Array(128)));
}
})

(await fetch(...)).body ReadableStreamHTTP

fetch()
FirefoxSafari
Gyazo

MDN
MDN body ReadableStream 使調https://github.com/whatwg/fetch/pull/425#issuecomment-462634914
Gyazo

Google Chrome使
Google ChromeBeta使Version 85.0.4183.38 (Official Build) beta (64-bit)

Chrome Beta: Google Chrome Beta - Google Chrome
使 chrome://flags/ Experimental Web Platform featuresEnabled使
Gyazo

1
Gyazo

<input> ReadableStreamfetch()POST
javascript
const readableStream = new ReadableStream({
start(ctrl) {
const encoder = new TextEncoder();
window.myinput.onkeyup = (ev) => {
if (ev.key === 'Enter') {
ctrl.enqueue(encoder.encode(ev.target.value+'\n'));
ev.target.value = '';
}
}
}
});
fetch("https://ppng.io/mytext", {
method: 'POST',
body: readableStream,
headers: { 'Content-Type': 'text/plain;charset=UTF-8' },
allowHTTP1ForStreamingUpload: true,
});
allowHTTP1ForStreamingUpload: true Google ChromeHTTP/1.1https://github.com/chromium/chromium/commit/4c75c0c9f730589ad8d6c33af919d6b105be1462#diff-0f684d35848d8674d6bd9c5673588856

POSThttps://ppng.io/Piping Server
Piping Server使 POST /hogehoge GET /hogehoge
https://ppng.io/mytext

Piping ServerDocker docker run -p 8181:8080 nwtgck/piping-server Piping Server

readableStream.pipeThrough(new TextEncoderStream()) 使使: https://github.com/nwtgck/piping-server-streaming-upload-htmls/blob/a107dd1fb1bbee9991a9278b10d9eaf88b52c395/text_stream_with_text_encoder_stream.html

video_player.html使
Gyazo

MediaStreamReadableStream
javascript
(async () => {
// Get display
const mediaStream = await navigator.mediaDevices.getDisplayMedia({video: true});
// Convert MediaStream to ReadableStream
const readableStream = mediaStreamToReadableStream(mediaStream, 100);
fetch("https://ppng.io/myvideo", {
method: 'POST',
body: readableStream,
allowHTTP1ForStreamingUpload: true,
});
})();
// Convert MediaStream to ReadableStream
function mediaStreamToReadableStream(mediaStream, timeslice) {
return new ReadableStream({
start(ctrl){
const recorder = new MediaRecorder(mediaStream);
recorder.ondataavailable = async (e) => {
ctrl.enqueue(new Uint8Array(await e.data.arrayBuffer()));
};
recorder.start(timeslice);
}
});
}

navigator.mediaDevices.getDisplayMedia({video: true}) MediaStream
MediaStreamReadableStreamfetch()POST

video
html
<video src="https://ppng.io/myvideo" autoplay muted></video>
Piping Server使
POST /myvideo /myvideo video

videoffplay使
curlffplay
bash
curl https://ppng.io/myvideo | ffplay -

fetch()ReadableStreamPOSTWebPOST

curlWeb

WebinMediaStream
const mediaStream =
javascript
//
navigator.mediaDevices.getUserMedia({ audio: { echoCancellation: true } })

javascript
// +
navigator.mediaDevices.getUserMedia({ video: true, audio: { echoCancellation: true } })



HTMLcanvas .captureStream() MediaStream
videocanvasMediaStreamMediaStream
調JSManipulate
javascript
// ......
// 調
async function sepiaMediaStream(mediaStream) {
const memVideo = document.createElement('video');
memVideo.srcObject = mediaStream;
await memVideo.play();
const width = memVideo.videoWidth;
const height = memVideo.videoHeight;
const srcCanvas = document.createElement('canvas');
const dstCanvas = document.createElement('canvas');
srcCanvas.width = dstCanvas.width = width;
srcCanvas.height = dstCanvas.height = height;
const srcCtx = srcCanvas.getContext('2d');
const dstCtx = dstCanvas.getContext('2d');
(function loop(){
srcCtx.drawImage(memVideo, 0, 0, width, height);
const frame = srcCtx.getImageData(0, 0, width, height);
JSManipulate.sepia.filter(frame);
dstCtx.putImageData(frame, 0, 0);
setTimeout(loop, 0);
})();
return dstCanvas.captureStream();
}

canvas
MediaStreamSnowSnap CameraWeb

canvas
WebGLcanvasthree.js JavaScript 3D librarycanvas
WebARVRWebXRcanvas使
canvasMediaStream

E2E
E2E

OpenPGP.js
readableStreampassword
javascript
// Encrypt ReadableStream with password by OpenPGP
async function encryptStream(readableStream, password) {
const options = {
message: openpgp.message.fromBinary(readableStream),
passwords: [password],
armor: false
};
const ciphertext = await openpgp.encrypt(options);
return ciphertext.message.packets.write();
}

PWA使Service Worker
https://localhost:8080/e2ee_screen_share/swvideo#myvideo" HTTPGET

WebWeb CryptoWeb Crypto &

E2E
E2E

fetch() fetch()WebE2E

Gyazo

Chrome readableStream.pipeThrough(new CompressionStream('gzip')) gzip
javascript
const readableStream = new ReadableStream({
pull(ctrl) {
// random bytes
ctrl.enqueue(window.crypto.getRandomValues(new Uint32Array(128)));
}
}).pipeThrough(new CompressionStream('gzip'))
fetch("https://ppng.io/mytext", {
method: 'POST',
body: readableStream,
allowHTTP1ForStreamingUpload: true,
});

ReadableStreamgzip

ffmpegEmscriptenReadableStream

HTTP
Gyazo

XMLHTTPRequestfetch
ReadableStream""
chunk.byteLength
javascript
//
const readableStreamWithProgress = readableStream.pipeThrough(progressStream(loaded => {
const progress = window.progress_bar.value = loaded / file.size * 100;
window.message.innerText = `${loaded} bytes (${progress.toFixed(2)}%)`;
}));
// ......
function progressStream(callback) {
let loaded = 0;
callback(loaded);
return new TransformStream({
transform(chunk, ctrl) {
ctrl.enqueue(chunk);
loaded += chunk.byteLength;
callback(loaded);
}
});
}



fetch()ReadableStream
javascript
const supportsRequestStreams = !new Request('', {
body: new ReadableStream(),
method: 'POST',
}).headers.has('Content-Type');

ReadableStream "[object ReadableStream]" Content-Type: text/plain ...

ReadableStream

Piping Server - QiitaHTTPSSHcurlsocat
WebSSHHTTPSSHVNC

Chrome
Streaming requests with the fetch APIGoogle Chrome
const res = await fetch(...) res.body ReadableStreamPromiseresolve await

2HTTP/2TCPHTTP2HTTP

fetch()ReadableStream
ReadableStream使
ReadableStream
<canvas>ReadableStreamHTTP

使
README python3 -m http.server https://localhost:8000
https://ppng.io/hogehoge hogehoge
Piping ServerPiping Server

HTTP/1.1Transfer-Encoding: chunked調

HTTP11110TBREST APIWebHTTPHTTP

curlWebstable