Skip to content

Commit 66e58a7

Browse files
committed
Add support for Want-Digest on LDP-RSs
Resolves #33
1 parent 0a83e44 commit 66e58a7

File tree

7 files changed

+93
-48
lines changed

7 files changed

+93
-48
lines changed

src/Controller/ResourceController.php

Lines changed: 4 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -13,15 +13,6 @@
1313

1414
class ResourceController implements ControllerProviderInterface
1515
{
16-
const LDP_NS = "http://www.w3.org/ns/ldp#";
17-
const RDF_NS = "http://www.w3.org/1999/02/22-rdf-syntax-ns#";
18-
const DCTERMS_NS = "http://purl.org/dc/terms/";
19-
20-
// Its a class, no need to pass all via arguments around.
21-
private $modifiedTime = null;
22-
private $contentLength = 0;
23-
private $eTag = null;
24-
2516
/**
2617
* {@inheritdoc}
2718
*/
@@ -59,12 +50,13 @@ public function get(Application $app, Request $request, $path)
5950
return new Response("Not Found", 404);
6051
}
6152

62-
//$responseFormat = $this->getResponseFormat($app['config']['validRdfFormats'], $request);
63-
//$responseMimeType = $this->getResponseMimeType($app['config']['validRdfFormats'], $request);
6453
$formats = $app['config']['validRdfFormats'];
54+
$options = [
55+
"contentDisposition" => $app['config']['contentDisposition']
56+
];
6557

6658
$resource = ResourceFactory::create($requestedPath, $formats);
67-
return $resource->respond($app, $request);
59+
return $resource->respond($app, $request, $options);
6860
}
6961

7062
/**

src/Model/BasicContainer.php

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,9 @@
66
use Symfony\Component\HttpFoundation\Request;
77
use Symfony\Component\HttpFoundation\Response;
88

9+
/**
10+
* A class representing an LDP BasicContainer
11+
*/
912
class BasicContainer extends Resource
1013
{
1114
/**
@@ -25,11 +28,13 @@ public function respond(Application $app, Request $request, array $options = arr
2528
];
2629

2730
$res = new Response();
31+
$res->setPublic();
2832
$res->headers->add($headers);
2933
$res->setLastModified($modifiedTime);
3034
$res->setEtag($this->getEtag($responseFormat, $request->headers->get('range')));
3135

3236
if (!$res->isNotModified($request)) {
37+
$algorithm = $this->getDigestAlgorithm($request->headers->get('want-digest'));
3338
$subject = $request->getUri();
3439
$predicate = self::LDP_NS . "contains";
3540

@@ -73,11 +78,22 @@ public function respond(Application $app, Request $request, array $options = arr
7378
$data = json_decode($graph->serialise("jsonld"), true);
7479
$dataset = $this->mapJsonLdForHTML($data, $app['config']['prefixes']);
7580
$template = $app['config']['template'];
76-
return $app['twig']->render($template, ["id" => $subject, "dataset" => $dataset]);
81+
$content = $app['twig']->render($template, ["id" => $subject, "dataset" => $dataset]);
7782
} else {
7883
$content = $graph->serialise($responseFormat);
7984
}
8085

86+
if ($request->headers->get('range') === null) {
87+
switch ($algorithm) {
88+
case "md5":
89+
$res->headers->set('Digest', 'md5=' . $this->md5($content));
90+
break;
91+
case "sha1":
92+
$res->headers->set('Digest', 'sha1=' . $this->sha1($content));
93+
break;
94+
}
95+
}
96+
8197
$res->setContent($content);
8298
}
8399

src/Model/NonRDFSource.php

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,9 @@
66
use Symfony\Component\HttpFoundation\Request;
77
use Symfony\Component\HttpFoundation\Response;
88

9+
/**
10+
* A class representing an LDP NonRDFSource
11+
*/
912
class NonRDFSource extends Resource
1013
{
1114
/**
@@ -18,13 +21,19 @@ public function respond(Application $app, Request $request, array $options = arr
1821
$contentDisposition = $options['contentDisposition'];
1922
}
2023
$res = new Response();
24+
$res->setPublic();
2125
$res->headers->add($this->getHeaders($contentDisposition));
2226
$res->setLastModified(\DateTime::createFromFormat('U', filemtime($this->path)));
2327
$res->setEtag($this->getEtag($request->headers->get('range')));
2428
if (!$res->isNotModified($request)) {
25-
$digest = $this->wantDigest($request->headers->get('want-digest'));
26-
if ($digest) {
27-
$res->headers->set('Digest', $digest);
29+
$algorithm = $this->getDigestAlgorithm($request->headers->get('want-digest'));
30+
switch ($algorithm) {
31+
case "md5":
32+
$res->headers->set('Digest', "md5=" . $this->md5());
33+
break;
34+
case "sha1":
35+
$res->headers->set('Digest', "sha1=" . $this->sha1());
36+
break;
2837
}
2938
foreach ($this->formats as $type) {
3039
$description = $this->path . "." . $type['extension'];

src/Model/RDFSource.php

Lines changed: 27 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,9 @@
66
use Symfony\Component\HttpFoundation\Request;
77
use Symfony\Component\HttpFoundation\Response;
88

9+
/**
10+
* A class representing an LDP RDFSource
11+
*/
912
class RDFSource extends Resource
1013
{
1114
/**
@@ -17,6 +20,7 @@ public function respond(Application $app, Request $request, array $options = arr
1720
$responseFormat = $this->getResponseFormat($request);
1821

1922
$res = new Response();
23+
$res->setPublic();
2024
$res->headers->add($this->getHeaders($responseMimeType));
2125
$res->setLastModified(\DateTime::createFromFormat('U', filemtime($this->path)));
2226
$res->setEtag($this->getEtag($responseFormat, $request->headers->get('range')));
@@ -32,10 +36,17 @@ public function respond(Application $app, Request $request, array $options = arr
3236
}
3337
}
3438

39+
$algorithm = $this->getDigestAlgorithm($request->headers->get('want-digest'));
3540
if ($this->canStream($responseFormat)) {
36-
$digest = $this->wantDigest($request->headers->get('want-digest'));
37-
if ($digest) {
38-
$res->headers->set('Digest', $digest);
41+
if ($request->headers->get('range') === null) {
42+
switch ($algorithm) {
43+
case "md5":
44+
$res->headers->set('Digest', 'md5=' . $this->md5());
45+
break;
46+
case "sha1":
47+
$res->headers->set('Digest', 'sha1=' . $this->sha1());
48+
break;
49+
}
3950
}
4051
$filename = $this->path;
4152
$stream = function () use ($filename) {
@@ -49,10 +60,21 @@ public function respond(Application $app, Request $request, array $options = arr
4960
$data = json_decode($graph->serialise("jsonld"), true);
5061
$dataset = $this->mapJsonLdForHTML($data, $app['config']['prefixes']);
5162
$template = $app['config']['template'];
52-
return $app['twig']->render($template, ["id" => $request->getURI(), "dataset" => $dataset]);
63+
$content = $app['twig']->render($template, ["id" => $request->getURI(), "dataset" => $dataset]);
5364
} else {
54-
$res->setContent($graph->serialise($responseFormat));
65+
$content = $graph->serialise($responseFormat);
5566
}
67+
if ($request->headers->get('range') === null) {
68+
switch ($algorithm) {
69+
case "md5":
70+
$res->headers->set('Digest', 'md5=' . $this->md5($content));
71+
break;
72+
case "sha1":
73+
$res->headers->set('Digest', 'sha1=' . $this->sha1($content));
74+
break;
75+
}
76+
}
77+
$res->setContent($content);
5678
}
5779
}
5880
return $res;

src/Model/Resource.php

Lines changed: 29 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,9 @@
55
use Silex\Application;
66
use Symfony\Component\HttpFoundation\Request;
77

8+
/**
9+
* A class representing an LDP Resource
10+
*/
811
abstract class Resource
912
{
1013
const LDP_NS = "http://www.w3.org/ns/ldp#";
@@ -42,60 +45,59 @@ abstract public function respond(Application $app, Request $request, array $opti
4245
* @return string
4346
* The SHA1 checksum of the file
4447
*/
45-
public function sha1()
48+
public function sha1($content = null)
4649
{
47-
if (is_file($this->path)) {
50+
if ($content !== null) {
51+
return sha1($content);
52+
} elseif (is_file($this->path)) {
4853
return sha1_file($this->path);
4954
}
5055
return null;
5156
}
5257

5358
/**
54-
* Apply a want-digest header, if applicable
59+
* Compute the MD5 checksum of a file
60+
* @return string
61+
* The MD5 checksum of the file
62+
*/
63+
public function md5($content = null)
64+
{
65+
if ($content !== null) {
66+
return md5($content);
67+
} elseif (is_file($this->path)) {
68+
return md5_file($this->path);
69+
}
70+
return null;
71+
}
72+
73+
/**
74+
* Given a want-digest header, return the applicable algorithm
5575
*
5676
* @param $wantDigestHeader
5777
* The Want-Digest header
5878
* @return string
59-
* The instance digest, if relevant
79+
* The algorithm name, if any
6080
*/
61-
protected function wantDigest($wantDigestHeader)
81+
protected function getDigestAlgorithm($wantDigestHeader)
6282
{
83+
$validAlgorithms = ["md5", "sha1"];
84+
$bestAlgorithm = null;
6385
if ($wantDigestHeader) {
6486
$maxQVal = 0.0;
65-
$bestAlgorithm = null;
6687
foreach (explode(",", $wantDigestHeader) as $algorithm) {
6788
$parts = explode(";", $algorithm);
6889
$qVal = 1.0;
6990
if (count($parts) > 1 && strpos($parts[1], "q=") === 0) {
7091
$qVal = floatval(trim(substr($parts[1], 2)));
7192
}
7293
$alg = strtolower(trim($parts[0]));
73-
if ($qVal > $maxQVal && in_array($alg, ["md5", "sha1"])) {
94+
if ($qVal > $maxQVal && in_array($alg, $validAlgorithms)) {
7495
$bestAlgorithm = $alg;
7596
$maxQVal = $qVal;
7697
}
7798
}
78-
switch($bestAlgorithm) {
79-
case "md5":
80-
return "md5=" . $this->md5();
81-
case "sha1":
82-
return "sha1=" . $this->sha1();
83-
}
8499
}
85-
return null;
86-
}
87-
88-
/**
89-
* Compute the MD5 checksum of a file
90-
* @return string
91-
* The MD5 checksum of the file
92-
*/
93-
public function md5()
94-
{
95-
if (is_file($this->path)) {
96-
return md5_file($this->path);
97-
}
98-
return null;
100+
return $bestAlgorithm;
99101
}
100102

101103
/**

src/TrellisConfiguration.php

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,9 @@ public function getConfigTreeBuilder()
2727
->booleanNode('debug')
2828
->defaultFalse()
2929
->end()
30+
->booleanNode('contentDisposition')
31+
->defaultFalse()
32+
->end()
3033
->arrayNode('validRdfFormats')
3134
->prototype("array")
3235
->children()

test/Model/RDFSourceTest.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ public function testGetRDFSource()
4242
$this->client->request('GET', "/nobel_914.ttl", [], [], ['HTTP_ACCEPT' => $request_mime]);
4343
$this->assertEquals(200, $this->client->getResponse()->getStatusCode(), "GET should be allowed.");
4444
$response = $this->client->getResponse();
45+
$response->sendContent();
4546
$charset = $response->getCharset();
4647
$expected_mime = "{$request_mime}; charset={$charset}";
4748

0 commit comments

Comments
 (0)