@@ -27,26 +27,71 @@ const checkPatchOverrideSupport = function (req, res) {
2727}
2828
2929/**
30- * Middleware to validate Content-Type headers.
31- * Ensures that requests carrying bodies have an appropriate Content-Type before
32- * reaching controllers, preventing unhandled errors from unparsed or mis-parsed bodies.
30+ * Middleware to validate JSON Content-Type headers for endpoints recieving JSON bodies.
3331 *
34- * - Skips validation for methods that don't carry bodies (GET, HEAD, OPTIONS, DELETE)
35- * - Skips validation for endpoints that don't carry bodies (/release)
36- * - Allows text/plain for /search endpoints (which accept plain text search terms)
37- * - Requires application/json or application/ld+json for all other write endpoints
38- * - Returns 415 for missing or unsupported Content-Type
32+ * @param {Object } req - Express request object
33+ * @param {Object } res - Express response object
34+ * @param {Function } next - Express next middleware function
35+ */
36+ const jsonContent = function ( req , res , next ) {
37+ const contentType = ( req . get ( "Content-Type" ) ?? "" ) . toLowerCase ( )
38+ const mimeType = contentType . split ( ";" ) [ 0 ] . trim ( )
39+ if ( ! mimeType ) {
40+ return next ( createExpressError ( {
41+ statusCode : 415 ,
42+ statusMessage : `Missing or empty Content-Type header.`
43+ } ) )
44+ }
45+ if ( contentType . includes ( "," ) ) {
46+ return next ( createExpressError ( {
47+ statusCode : 415 ,
48+ statusMessage : `Multiple Content-Type values are not allowed. Provide exactly one Content-Type header.`
49+ } ) )
50+ }
51+ if ( mimeType === "application/json" || mimeType === "application/ld+json" ) return next ( )
52+ return next ( createExpressError ( {
53+ statusCode : 415 ,
54+ statusMessage : `Unsupported Content-Type: ${ contentType } . This endpoint requires application/json or application/ld+json.`
55+ } ) )
56+ }
57+
58+ /**
59+ * Middleware to validate Content-Type headers for endpoints recieving textual bodies.
3960 *
4061 * @param {Object } req - Express request object
4162 * @param {Object } res - Express response object
4263 * @param {Function } next - Express next middleware function
4364 */
44- const SKIP_CONTENT_TYPE_METHODS = [ "GET" , "HEAD" , "OPTIONS" , "DELETE" ]
45- const validateContentType = function ( req , res , next ) {
46- const isReleaseEndpoint = req . path === "/release" || req . path . startsWith ( "/release/" )
47- if ( SKIP_CONTENT_TYPE_METHODS . includes ( req . method ) || isReleaseEndpoint ) {
48- return next ( )
65+ const textContent = function ( req , res , next ) {
66+ const contentType = ( req . get ( "Content-Type" ) ?? "" ) . toLowerCase ( )
67+ const mimeType = contentType . split ( ";" ) [ 0 ] . trim ( )
68+ if ( ! mimeType ) {
69+ return next ( createExpressError ( {
70+ statusCode : 415 ,
71+ statusMessage : `Missing or empty Content-Type header.`
72+ } ) )
73+ }
74+ if ( contentType . includes ( "," ) ) {
75+ return next ( createExpressError ( {
76+ statusCode : 415 ,
77+ statusMessage : `Multiple Content-Type values are not allowed. Provide exactly one Content-Type header.`
78+ } ) )
4979 }
80+ if ( mimeType === "text/plain" ) return next ( )
81+ return next ( createExpressError ( {
82+ statusCode : 415 ,
83+ statusMessage : `Unsupported Content-Type: ${ contentType } . This endpoint requires text/plain.`
84+ } ) )
85+ }
86+
87+ /**
88+ * Middleware to validate Content-Type headers for endpoints recieving either JSON or textual bodies.
89+ *
90+ * @param {Object } req - Express request object
91+ * @param {Object } res - Express response object
92+ * @param {Function } next - Express next middleware function
93+ */
94+ const eitherContent = function ( req , res , next ) {
5095 const contentType = ( req . get ( "Content-Type" ) ?? "" ) . toLowerCase ( )
5196 const mimeType = contentType . split ( ";" ) [ 0 ] . trim ( )
5297 if ( ! mimeType ) {
@@ -61,13 +106,10 @@ const validateContentType = function (req, res, next) {
61106 statusMessage : `Multiple Content-Type values are not allowed. Provide exactly one Content-Type header.`
62107 } ) )
63108 }
64- if ( mimeType === "application/json" || mimeType === "application/ld+json" ) return next ( )
65- const isSearchEndpoint = req . path === "/search" || req . path . startsWith ( "/search/" )
66- if ( mimeType === "text/plain" && isSearchEndpoint ) return next ( )
67- const acceptedTypes = `application/json or application/ld+json${ isSearchEndpoint ? ' or text/plain' : '' } `
109+ if ( mimeType === "text/plain" || mimeType === "application/json" || mimeType === "application/ld+json" ) return next ( )
68110 return next ( createExpressError ( {
69111 statusCode : 415 ,
70- statusMessage : `Unsupported Content-Type: ${ contentType } . This endpoint requires ${ acceptedTypes } .`
112+ statusMessage : `Unsupported Content-Type: ${ contentType } . This endpoint requires text/plain .`
71113 } ) )
72114}
73115
@@ -163,4 +205,4 @@ It may not have completed at all, and most likely did not complete successfully.
163205 res . status ( error . status ) . send ( error . message )
164206}
165207
166- export default { checkPatchOverrideSupport, validateContentType , messenger }
208+ export default { checkPatchOverrideSupport, jsonContent , textContent , messenger }
0 commit comments