1+ // Express handler for LDP PATCH requests
2+
13module . exports = handler
24
3- var bodyParser = require ( 'body-parser' )
4- var mime = require ( 'mime-types' )
5- var fs = require ( 'fs' )
6- var debug = require ( '../debug' ) . handlers
7- var utils = require ( '../utils.js' )
8- var error = require ( '../http-error' )
9- var $rdf = require ( 'rdflib' )
5+ const bodyParser = require ( 'body-parser' )
6+ const mime = require ( 'mime-types' )
7+ const fs = require ( 'fs' )
8+ const debug = require ( '../debug' ) . handlers
9+ const utils = require ( '../utils.js' )
10+ const error = require ( '../http-error' )
11+ const $rdf = require ( 'rdflib' )
1012
11- const DEFAULT_CONTENT_TYPE = 'text/turtle'
13+ const DEFAULT_TARGET_TYPE = 'text/turtle'
1214
15+ // Patch handlers by request body content type
1316const PATCHERS = {
1417 'application/sparql-update' : require ( './patch/sparql-update-patcher.js' )
1518}
1619
17- const readEntity = bodyParser . text ( { type : '*/*' } )
18-
19- function handler ( req , res , next ) {
20- readEntity ( req , res , ( ) => patchHandler ( req , res , next ) )
21- }
22-
20+ // Handles a PATCH request
2321function patchHandler ( req , res , next ) {
24- const patchText = req . body ? req . body . toString ( ) : ''
2522 debug ( 'PATCH -- ' + req . originalUrl )
26- debug ( 'PATCH -- Received patch (%d bytes)' , patchText . length )
2723 res . header ( 'MS-Author-Via' , 'SPARQL' )
2824
29- var ldp = req . app . locals . ldp
30- var root = ! ldp . idp ? ldp . root : ldp . root + req . hostname + '/'
31- var targetFile = utils . uriToFilename ( req . path , root )
32- var targetContentType = mime . lookup ( targetFile ) || DEFAULT_CONTENT_TYPE
33- var patchContentType = req . get ( 'content-type' )
34- ? req . get ( 'content-type' ) . split ( ';' ) [ 0 ] . trim ( ) // Ignore parameters
35- : ''
36- var targetURI = utils . uriAbs ( req ) + req . originalUrl
37-
38- debug ( 'PATCH -- Content-type ' + patchContentType + ' patching target ' + targetContentType + ' <' + targetURI + '>' )
39-
40- // Obtain a patcher for the given patch type
41- const patchGraph = PATCHERS [ patchContentType ]
25+ // Obtain details of the patch document
26+ const patch = {
27+ text : req . body ? req . body . toString ( ) : '' ,
28+ contentType : ( req . get ( 'content-type' ) || '' ) . match ( / ^ [ ^ ; \s ] * / ) [ 0 ]
29+ }
30+ const patchGraph = PATCHERS [ patch . contentType ]
4231 if ( ! patchGraph ) {
43- return next ( error ( 415 , 'Unknown patch content type: ' + patchContentType ) )
32+ return next ( error ( 415 , 'Unknown patch content type: ' + patch . contentType ) )
33+ }
34+ debug ( 'PATCH -- Received patch (%d bytes, %s)' , patch . text . length , patch . contentType )
35+
36+ // Obtain details of the target resource
37+ const ldp = req . app . locals . ldp
38+ const root = ! ldp . idp ? ldp . root : ldp . root + req . hostname + '/'
39+ const target = {
40+ file : utils . uriToFilename ( req . path , root ) ,
41+ uri : utils . uriAbs ( req ) + req . originalUrl
4442 }
43+ target . contentType = mime . lookup ( target . file ) || DEFAULT_TARGET_TYPE
44+ debug ( 'PATCH -- Target <%s> (%s)' , target . uri , target . contentType )
4545
4646 // Read the RDF graph to be patched from the file
47- readGraph ( targetFile , targetURI , targetContentType )
47+ readGraph ( target )
4848 // Patch the graph and write it back to the file
49- . then ( targetKB => patchGraph ( targetKB , targetFile , targetURI , patchText ) )
50- . then ( targetKB => writeGraph ( targetKB , targetFile , targetURI , targetContentType ) )
49+ . then ( graph => patchGraph ( graph , target . uri , patch . text ) )
50+ . then ( graph => writeGraph ( graph , target ) )
5151 // Send the result to the client
5252 . then ( result => { res . send ( result ) } )
5353 . then ( next , next )
5454}
5555
56- // Reads the RDF graph in the given file with the corresponding URI
57- function readGraph ( resourceFile , resourceURI , contentType ) {
58- // Read the file
56+ // Reads the request body and calls the actual patch handler
57+ function handler ( req , res , next ) {
58+ readEntity ( req , res , ( ) => patchHandler ( req , res , next ) )
59+ }
60+ const readEntity = bodyParser . text ( { type : ( ) => true } )
61+
62+ // Reads the RDF graph in the given resource
63+ function readGraph ( resource ) {
64+ // Read the resource's file
5965 return new Promise ( ( resolve , reject ) =>
60- fs . readFile ( resourceFile , { encoding : 'utf8' } , function ( err , fileContents ) {
66+ fs . readFile ( resource . file , { encoding : 'utf8' } , function ( err , fileContents ) {
6167 if ( err ) {
6268 // If the file does not exist, assume empty contents
6369 // (it will be created after a successful patch)
@@ -72,27 +78,27 @@ function readGraph (resourceFile, resourceURI, contentType) {
7278 resolve ( fileContents )
7379 } )
7480 )
75- // Parse the file
81+ // Parse the resource's file contents
7682 . then ( ( fileContents ) => {
7783 const graph = $rdf . graph ( )
78- debug ( 'PATCH -- Reading %s with content type %s' , resourceURI , contentType )
84+ debug ( 'PATCH -- Reading %s with content type %s' , resource . uri , resource . contentType )
7985 try {
80- $rdf . parse ( fileContents , graph , resourceURI , contentType )
86+ $rdf . parse ( fileContents , graph , resource . uri , resource . contentType )
8187 } catch ( err ) {
82- throw error ( 500 , 'Patch: Target ' + contentType + ' file syntax error:' + err )
88+ throw error ( 500 , 'Patch: Target ' + resource . contentType + ' file syntax error:' + err )
8389 }
8490 debug ( 'PATCH -- Parsed target file' )
8591 return graph
8692 } )
8793}
8894
89- // Writes the RDF graph to the given file
90- function writeGraph ( graph , resourceFile , resourceURI , contentType ) {
95+ // Writes the RDF graph to the given resource
96+ function writeGraph ( graph , resource ) {
9197 return new Promise ( ( resolve , reject ) => {
92- const resource = graph . sym ( resourceURI )
93- const serialized = $rdf . serialize ( resource , graph , resourceURI , contentType )
98+ const resourceSym = graph . sym ( resource . uri )
99+ const serialized = $rdf . serialize ( resourceSym , graph , resource . uri , resource . contentType )
94100
95- fs . writeFile ( resourceFile , serialized , { encoding : 'utf8' } , function ( err ) {
101+ fs . writeFile ( resource . file , serialized , { encoding : 'utf8' } , function ( err ) {
96102 if ( err ) {
97103 return reject ( error ( 500 , 'Failed to write file back after patch: ' + err ) )
98104 }
0 commit comments