Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add method opt to overwrite http method #322

Merged
merged 2 commits into from
Jun 18, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -388,6 +388,10 @@ through `JSON.stringify()`.
Setting this option for GET, HEAD requests will throw an error "Rewriting the body when doing a {GET|HEAD} is not allowed".
Setting this option to `null` will strip the body (and `content-type` header) entirely from the proxied request.

#### `method`

Replaces the original request method with what is specified.

#### `retriesCount`

How many times it will try to pick another connection on socket hangup (`ECONNRESET` error).
Expand Down
9 changes: 5 additions & 4 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ const fastifyReplyFrom = fp(function from (fastify, opts, next) {
fastify.decorateReply('from', function (source, opts) {
opts = opts || {}
const req = this.request.raw
const method = opts.method || req.method
const onResponse = opts.onResponse
const rewriteHeaders = opts.rewriteHeaders || headersNoOp
const rewriteRequestHeaders = opts.rewriteRequestHeaders || requestHeadersNoOp
Expand Down Expand Up @@ -127,12 +128,12 @@ const fastifyReplyFrom = fp(function from (fastify, opts, next) {
// fastify ignore message body when it's a GET or HEAD request
// when proxy this request, we should reset the content-length to make it a valid http request
// discussion: https://github.com/fastify/fastify/issues/953
if (req.method === 'GET' || req.method === 'HEAD') {
if (method === 'GET' || method === 'HEAD') {
// body will be populated here only if opts.body is passed.
// if we are doing that with a GET or HEAD request is a programmer error
// and as such we can throw immediately.
if (body) {
throw new Error(`Rewriting the body when doing a ${req.method} is not allowed`)
throw new Error(`Rewriting the body when doing a ${method} is not allowed`)
}
}

Expand All @@ -141,13 +142,13 @@ const fastifyReplyFrom = fp(function from (fastify, opts, next) {
const requestHeaders = rewriteRequestHeaders(this.request, headers)
const contentLength = requestHeaders['content-length']
let requestImpl
if (retryMethods.has(req.method) && !contentLength) {
if (retryMethods.has(method) && !contentLength) {
requestImpl = createRequestRetry(request, this, retriesCount, retryOnError, maxRetriesOn503)
} else {
requestImpl = request
}

requestImpl({ method: req.method, url, qs, headers: requestHeaders, body }, (err, res) => {
requestImpl({ method, url, qs, headers: requestHeaders, body }, (err, res) => {
if (err) {
this.request.log.warn(err, 'response errored')
if (!this.sent) {
Expand Down
70 changes: 70 additions & 0 deletions test/method.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
'use strict'

const t = require('tap')
const Fastify = require('fastify')
const From = require('..')
const http = require('http')
const get = require('simple-get').concat

const instance = Fastify()

t.plan(9)
t.teardown(instance.close.bind(instance))

const bodyString = JSON.stringify({ hello: 'world' })

const parsedLength = Buffer.byteLength(bodyString)

const target = http.createServer((req, res) => {
t.pass('request proxied')
t.equal(req.method, 'POST')
t.equal(req.headers['content-type'], 'application/json')
t.same(req.headers['content-length'], parsedLength)
let data = ''
req.setEncoding('utf8')
req.on('data', (d) => {
data += d
})
req.on('end', () => {
t.same(JSON.parse(data), { hello: 'world' })
res.statusCode = 200
res.setHeader('content-type', 'application/json')
res.end(JSON.stringify({ something: 'else' }))
})
})

instance.patch('/', (request, reply) => {
reply.from(`http://localhost:${target.address().port}`, { method: 'POST' })
})

t.teardown(target.close.bind(target))

target.listen({ port: 0 }, (err) => {
t.error(err)

instance.addContentTypeParser('application/json', function (req, payload, done) {
done(null, payload)
})

instance.register(From, {
base: `http://localhost:${target.address().port}`,
undici: true
})

instance.listen({ port: 0 }, (err) => {
t.error(err)

get({
url: `http://localhost:${instance.server.address().port}`,
method: 'PATCH',
headers: {
'content-type': 'application/json'
},
body: bodyString
}, (err, res, data) => {
t.error(err)
const parsed = JSON.parse(data)
t.same(parsed, { something: 'else' })
})
})
})
1 change: 1 addition & 0 deletions types/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ declare namespace fastifyReplyFrom {
request: FastifyRequest<RequestGenericInterface, RawServerBase>,
base: string
) => string;
method?: HTTPMethods;
psteinroe marked this conversation as resolved.
Show resolved Hide resolved
}

interface Http2Options {
Expand Down
1 change: 1 addition & 0 deletions types/index.test-d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,7 @@ async function main() {

instance.get("/http2", (request, reply) => {
reply.from("/", {
method: "POST",
rewriteHeaders(headers, req) {
return headers;
},
Expand Down