summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--client.js77
-rw-r--r--connect.js6
-rw-r--r--examples/client.js8
-rw-r--r--examples/server.js6
4 files changed, 67 insertions, 30 deletions
diff --git a/client.js b/client.js
index 77dd88b..2edede7 100644
--- a/client.js
+++ b/client.js
@@ -1,32 +1,16 @@
'use strict'
+const {parse: parseUrl} = require('url')
const connect = require('./connect')
const createParser = require('./lib/response-parser')
const {
DEFAULT_PORT,
ALPN_ID,
} = require('./lib/util')
+const {CODES} = require('./lib/statuses')
-const sendGeminiRequest = (pathOrUrl, opt, cb) => {
- if (typeof pathOrUrl !== 'string' || !pathOrUrl) {
- throw new Error('pathOrUrl must be a string & not empty')
- }
- if (typeof opt === 'function') {
- cb = opt
- opt = {}
- }
- const {
- port,
- tlsOpt,
- } = {
- port: DEFAULT_PORT,
- tlsOpt: {},
- ...opt,
- }
-
- connect({
- port, tlsOpt,
- }, (err, socket) => {
+const _request = (pathOrUrl, opt, cb) => {
+ connect(opt, (err, socket) => {
if (err) return cb(err)
if (socket.alpnProtocol !== ALPN_ID) {
@@ -66,4 +50,57 @@ const sendGeminiRequest = (pathOrUrl, opt, cb) => {
})
}
+const sendGeminiRequest = (pathOrUrl, opt, cb) => {
+ if (typeof pathOrUrl !== 'string' || !pathOrUrl) {
+ throw new Error('pathOrUrl must be a string & not empty')
+ }
+ if (typeof opt === 'function') {
+ cb = opt
+ opt = {}
+ }
+ const {
+ followRedirects,
+ cert, key, passphrase,
+ tlsOpt,
+ } = {
+ followRedirects: false,
+ cert: null, key: null, passphrase: null,
+ tlsOpt: {},
+ ...opt,
+ }
+
+ const target = parseUrl(pathOrUrl)
+ const hostname = target.hostname || 'localhost'
+ const port = target.port || DEFAULT_PORT
+ const reqOpt = {
+ hostname, port,
+ cert, key, passphrase,
+ tlsOpt,
+ }
+
+ let onRes = cb
+ if (followRedirects) {
+ // todo: prevent endless redirects
+ onRes = (err, res) => {
+ if (err) return cb(err)
+
+ if (
+ res.statusCode === CODES.REDIRECT_TEMPORARY ||
+ res.statusCode === CODES.REDIRECT_PERMANENT
+ ) {
+ const newTarget = parseUrl(res.meta)
+ _request(res.meta, {
+ ...reqOpt,
+ host: newTarget.hostname || hostname,
+ port: newTarget.port || port,
+ }, onRes)
+ } else {
+ cb(null, res)
+ }
+ }
+ }
+
+ _request(pathOrUrl, reqOpt, onRes)
+}
+
module.exports = sendGeminiRequest
diff --git a/connect.js b/connect.js
index 35e2297..c606703 100644
--- a/connect.js
+++ b/connect.js
@@ -13,11 +13,11 @@ const connectToGeminiServer = (opt, cb) => {
opt = {}
}
const {
- host,
+ hostname,
port,
tlsOpt,
} = {
- host: '127.0.0.1',
+ hostname: '127.0.0.1',
port: DEFAULT_PORT,
tlsOpt: {},
// todo: TOFU via isTrustedCertificate()
@@ -27,7 +27,7 @@ const connectToGeminiServer = (opt, cb) => {
const socket = connectTls({
ALPNProtocols: [ALPN_ID],
minVersion: MIN_TLS_VERSION,
- host, port,
+ hostname, port,
// todo: cert, key, passphrase
...tlsOpt,
})
diff --git a/examples/client.js b/examples/client.js
index 1695335..49e38d0 100644
--- a/examples/client.js
+++ b/examples/client.js
@@ -1,16 +1,14 @@
'use strict'
-const {
- request,
- DEFAULT_PORT,
-} = require('..')
+const {request} = require('..')
const onError = (err) => {
console.error(err)
process.exit(1)
}
-request('/foo', {
+request('/bar', {
+ followRedirects: true,
tlsOpt: {
rejectUnauthorized: false,
},
diff --git a/examples/server.js b/examples/server.js
index bff88e3..2012c42 100644
--- a/examples/server.js
+++ b/examples/server.js
@@ -8,8 +8,10 @@ const {
const onRequest = (req, res) => {
if (req.path === '/foo') {
- res.write('foo,')
- res.end('bar')
+ res.write('foo')
+ res.end('!')
+ } else if (req.path === '/bar') {
+ res.redirect('/foo')
} else {
res.gone()
}