summaryrefslogtreecommitdiffstats
path: root/index.js
blob: 470b21de5a4bfb41bf87cc08eb4d4182e4ca02c7 (plain)
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
'use strict'

const {createServer: createTlsServer} = require('tls')
const {EventEmitter} = require('events')
const {createParser} = require('./lib/parser')
const createResponse = require('./lib/response')

const ALPN_ID = 'gemini' // todo: clarify this

const createGeminiServer = (opt = {}, onRequest) => {
	if (typeof opt === 'function') {
		onRequest = opt
		opt = {}
	}
	const {
		tlsOpt,
	} = {
		tlsOpt: {},
		...opt,
	}

	const onConnection = (socket) => {
		const req = createParser()
		socket.pipe(req)
		socket.once('error', (err) => {
			socket.unpipe(req)
			req.destroy(err)
		})

		const close = () => {
			socket.destroy()
			req.destroy()
		}
		let timeout = setTimeout(close, 20 * 1000)

		req.once('header', (header) => {
			clearTimeout(timeout)

			// prepare req
			req.socket = socket
			req.url = header.url
			const url = new URL(header.url, 'http://foo/')
			req.path = url.pathname
			// todo: req.abort(), req.destroy()

			// prepare res
			const res = createResponse()
			res.pipe(socket)
			res.once('error', (err) => {
				console.error('error', err)
				res.unpipe(socket)
				socket.destroy(err)
			})
			Object.defineProperty(res, 'socket', {value: socket})

			onRequest(req, res)
			server.emit('request', req, res)
		})
	}

	const server = createTlsServer({
		// ALPNProtocols: [ALPN_ID],
		// https://gemini.circumlunar.space/docs/spec-spec.txt#1.4.1
		// > Servers MUST use TLS version 1.2 or higher and SHOULD use TLS version
		// > 1.3 or higher.
		minVersion: 'TLSv1.2',
		...tlsOpt,
	}, onConnection)

	return server
}

// https://gemini.circumlunar.space/docs/spec-spec.txt, 1.
// > When Gemini is served over TCP/IP, servers should listen on port 1965
// > (the first manned Gemini mission, Gemini 3, flew in March '65).
createGeminiServer.DEFAULT_PORT = 1965

module.exports = createGeminiServer