UNPKG

3.92 kBJavaScriptView Raw
1'use strict'
2
3const { validate: validateSchema } = require('./validation')
4const { preValidationHookRunner, preHandlerHookRunner } = require('./hooks')
5const wrapThenable = require('./wrapThenable')
6const {
7 kReplyIsError,
8 kRouteContext
9} = require('./symbols')
10
11function handleRequest (err, request, reply) {
12 if (reply.sent === true) return
13 if (err != null) {
14 reply[kReplyIsError] = true
15 reply.send(err)
16 return
17 }
18
19 const method = request.raw.method
20 const headers = request.headers
21 const context = request[kRouteContext]
22
23 if (method === 'GET' || method === 'HEAD') {
24 handler(request, reply)
25 return
26 }
27
28 const contentType = headers['content-type']
29
30 if (method === 'POST' || method === 'PUT' || method === 'PATCH' || method === 'TRACE' || method === 'SEARCH' ||
31 method === 'PROPFIND' || method === 'PROPPATCH' || method === 'LOCK' || method === 'REPORT' || method === 'MKCALENDAR') {
32 if (contentType === undefined) {
33 if (
34 headers['transfer-encoding'] === undefined &&
35 (headers['content-length'] === '0' || headers['content-length'] === undefined)
36 ) { // Request has no body to parse
37 handler(request, reply)
38 } else {
39 context.contentTypeParser.run('', handler, request, reply)
40 }
41 } else {
42 context.contentTypeParser.run(contentType, handler, request, reply)
43 }
44 return
45 }
46
47 if (method === 'OPTIONS' || method === 'DELETE') {
48 if (
49 contentType !== undefined &&
50 (
51 headers['transfer-encoding'] !== undefined ||
52 headers['content-length'] !== undefined
53 )
54 ) {
55 context.contentTypeParser.run(contentType, handler, request, reply)
56 } else {
57 handler(request, reply)
58 }
59 return
60 }
61
62 // Return 404 instead of 405 see https://github.com/fastify/fastify/pull/862 for discussion
63 handler(request, reply)
64}
65
66function handler (request, reply) {
67 try {
68 if (request[kRouteContext].preValidation !== null) {
69 preValidationHookRunner(
70 request[kRouteContext].preValidation,
71 request,
72 reply,
73 preValidationCallback
74 )
75 } else {
76 preValidationCallback(null, request, reply)
77 }
78 } catch (err) {
79 preValidationCallback(err, request, reply)
80 }
81}
82
83function preValidationCallback (err, request, reply) {
84 if (reply.sent === true) return
85
86 if (err != null) {
87 reply[kReplyIsError] = true
88 reply.send(err)
89 return
90 }
91
92 const validationErr = validateSchema(reply[kRouteContext], request)
93 const isAsync = (validationErr && typeof validationErr.then === 'function') || false
94
95 if (isAsync) {
96 const cb = validationCompleted.bind(null, request, reply)
97 validationErr.then(cb, cb)
98 } else {
99 validationCompleted(request, reply, validationErr)
100 }
101}
102
103function validationCompleted (request, reply, validationErr) {
104 if (validationErr) {
105 if (reply[kRouteContext].attachValidation === false) {
106 reply.send(validationErr)
107 return
108 }
109
110 reply.request.validationError = validationErr
111 }
112
113 // preHandler hook
114 if (request[kRouteContext].preHandler !== null) {
115 preHandlerHookRunner(
116 request[kRouteContext].preHandler,
117 request,
118 reply,
119 preHandlerCallback
120 )
121 } else {
122 preHandlerCallback(null, request, reply)
123 }
124}
125
126function preHandlerCallback (err, request, reply) {
127 if (reply.sent) return
128
129 if (err != null) {
130 reply[kReplyIsError] = true
131 reply.send(err)
132 return
133 }
134
135 let result
136
137 try {
138 result = request[kRouteContext].handler(request, reply)
139 } catch (err) {
140 reply[kReplyIsError] = true
141 reply.send(err)
142 return
143 }
144
145 if (result !== undefined) {
146 if (result !== null && typeof result.then === 'function') {
147 wrapThenable(result, reply)
148 } else {
149 reply.send(result)
150 }
151 }
152}
153
154module.exports = handleRequest
155module.exports[Symbol.for('internals')] = { handler, preHandlerCallback }