1<?php 2 3namespace Sabre\DAV\Locks; 4 5use Sabre\DAV; 6use Sabre\HTTP; 7 8require_once 'Sabre/DAV/AbstractServer.php'; 9 10class PluginTest extends DAV\AbstractServer { 11 12 /** 13 * @var Plugin 14 */ 15 protected $locksPlugin; 16 17 function setUp() { 18 19 parent::setUp(); 20 $locksBackend = new Backend\File(SABRE_TEMPDIR . '/locksdb'); 21 $locksPlugin = new Plugin($locksBackend); 22 $this->server->addPlugin($locksPlugin); 23 $this->locksPlugin = $locksPlugin; 24 25 } 26 27 function testGetInfo() { 28 29 $this->assertArrayHasKey( 30 'name', 31 $this->locksPlugin->getPluginInfo() 32 ); 33 34 } 35 36 function testGetFeatures() { 37 38 $this->assertEquals([2], $this->locksPlugin->getFeatures()); 39 40 } 41 42 function testGetHTTPMethods() { 43 44 $this->assertEquals(['LOCK', 'UNLOCK'], $this->locksPlugin->getHTTPMethods('')); 45 46 } 47 48 function testLockNoBody() { 49 50 $request = new HTTP\Request('LOCK', '/test.txt'); 51 $this->server->httpRequest = $request; 52 $this->server->exec(); 53 54 $this->assertEquals([ 55 'X-Sabre-Version' => [DAV\Version::VERSION], 56 'Content-Type' => ['application/xml; charset=utf-8'], 57 ], 58 $this->response->getHeaders() 59 ); 60 61 $this->assertEquals(400, $this->response->status); 62 63 } 64 65 function testLock() { 66 67 $request = new HTTP\Request('LOCK', '/test.txt'); 68 $request->setBody('<?xml version="1.0"?> 69<D:lockinfo xmlns:D="DAV:"> 70 <D:lockscope><D:exclusive/></D:lockscope> 71 <D:locktype><D:write/></D:locktype> 72 <D:owner> 73 <D:href>http://example.org/~ejw/contact.html</D:href> 74 </D:owner> 75</D:lockinfo>'); 76 77 $this->server->httpRequest = $request; 78 $this->server->exec(); 79 80 $this->assertEquals('application/xml; charset=utf-8', $this->response->getHeader('Content-Type')); 81 $this->assertTrue(preg_match('/^<opaquelocktoken:(.*)>$/', $this->response->getHeader('Lock-Token')) === 1, 'We did not get a valid Locktoken back (' . $this->response->getHeader('Lock-Token') . ')'); 82 83 $this->assertEquals(200, $this->response->status, 'Got an incorrect status back. Response body: ' . $this->response->body); 84 85 $body = preg_replace("/xmlns(:[A-Za-z0-9_])?=(\"|\')DAV:(\"|\')/", "xmlns\\1=\"urn:DAV\"", $this->response->body); 86 $xml = simplexml_load_string($body); 87 $xml->registerXPathNamespace('d', 'urn:DAV'); 88 89 $elements = [ 90 '/d:prop', 91 '/d:prop/d:lockdiscovery', 92 '/d:prop/d:lockdiscovery/d:activelock', 93 '/d:prop/d:lockdiscovery/d:activelock/d:locktype', 94 '/d:prop/d:lockdiscovery/d:activelock/d:lockroot', 95 '/d:prop/d:lockdiscovery/d:activelock/d:lockroot/d:href', 96 '/d:prop/d:lockdiscovery/d:activelock/d:locktype/d:write', 97 '/d:prop/d:lockdiscovery/d:activelock/d:lockscope', 98 '/d:prop/d:lockdiscovery/d:activelock/d:lockscope/d:exclusive', 99 '/d:prop/d:lockdiscovery/d:activelock/d:depth', 100 '/d:prop/d:lockdiscovery/d:activelock/d:owner', 101 '/d:prop/d:lockdiscovery/d:activelock/d:timeout', 102 '/d:prop/d:lockdiscovery/d:activelock/d:locktoken', 103 '/d:prop/d:lockdiscovery/d:activelock/d:locktoken/d:href', 104 ]; 105 106 foreach ($elements as $elem) { 107 $data = $xml->xpath($elem); 108 $this->assertEquals(1, count($data), 'We expected 1 match for the xpath expression "' . $elem . '". ' . count($data) . ' were found. Full response body: ' . $this->response->body); 109 } 110 111 $depth = $xml->xpath('/d:prop/d:lockdiscovery/d:activelock/d:depth'); 112 $this->assertEquals('infinity', (string)$depth[0]); 113 114 $token = $xml->xpath('/d:prop/d:lockdiscovery/d:activelock/d:locktoken/d:href'); 115 $this->assertEquals($this->response->getHeader('Lock-Token'), '<' . (string)$token[0] . '>', 'Token in response body didn\'t match token in response header.'); 116 117 } 118 119 /** 120 * @depends testLock 121 */ 122 function testDoubleLock() { 123 124 $request = new HTTP\Request('LOCK', '/test.txt'); 125 $request->setBody('<?xml version="1.0"?> 126<D:lockinfo xmlns:D="DAV:"> 127 <D:lockscope><D:exclusive/></D:lockscope> 128 <D:locktype><D:write/></D:locktype> 129 <D:owner> 130 <D:href>http://example.org/~ejw/contact.html</D:href> 131 </D:owner> 132</D:lockinfo>'); 133 134 $this->server->httpRequest = $request; 135 $this->server->exec(); 136 137 $this->response = new HTTP\ResponseMock(); 138 $this->server->httpResponse = $this->response; 139 140 $this->server->exec(); 141 142 $this->assertEquals('application/xml; charset=utf-8', $this->response->getHeader('Content-Type')); 143 144 $this->assertEquals(423, $this->response->status, 'Full response: ' . $this->response->body); 145 146 } 147 148 /** 149 * @depends testLock 150 */ 151 function testLockRefresh() { 152 153 $request = new HTTP\Request('LOCK', '/test.txt'); 154 $request->setBody('<?xml version="1.0"?> 155<D:lockinfo xmlns:D="DAV:"> 156 <D:lockscope><D:exclusive/></D:lockscope> 157 <D:locktype><D:write/></D:locktype> 158 <D:owner> 159 <D:href>http://example.org/~ejw/contact.html</D:href> 160 </D:owner> 161</D:lockinfo>'); 162 163 $this->server->httpRequest = $request; 164 $this->server->exec(); 165 166 $lockToken = $this->response->getHeader('Lock-Token'); 167 168 $this->response = new HTTP\ResponseMock(); 169 $this->server->httpResponse = $this->response; 170 171 $request = new HTTP\Request('LOCK', '/test.txt', ['If' => '(' . $lockToken . ')']); 172 $request->setBody(''); 173 174 $this->server->httpRequest = $request; 175 $this->server->exec(); 176 177 $this->assertEquals('application/xml; charset=utf-8', $this->response->getHeader('Content-Type')); 178 179 $this->assertEquals(200, $this->response->status, 'We received an incorrect status code. Full response body: ' . $this->response->getBody()); 180 181 } 182 183 /** 184 * @depends testLock 185 */ 186 function testLockRefreshBadToken() { 187 188 $request = new HTTP\Request('LOCK', '/test.txt'); 189 $request->setBody('<?xml version="1.0"?> 190<D:lockinfo xmlns:D="DAV:"> 191 <D:lockscope><D:exclusive/></D:lockscope> 192 <D:locktype><D:write/></D:locktype> 193 <D:owner> 194 <D:href>http://example.org/~ejw/contact.html</D:href> 195 </D:owner> 196</D:lockinfo>'); 197 198 $this->server->httpRequest = $request; 199 $this->server->exec(); 200 201 $lockToken = $this->response->getHeader('Lock-Token'); 202 203 $this->response = new HTTP\ResponseMock(); 204 $this->server->httpResponse = $this->response; 205 206 $request = new HTTP\Request('LOCK', '/test.txt', ['If' => '(' . $lockToken . 'foobar) (<opaquelocktoken:anotherbadtoken>)']); 207 $request->setBody(''); 208 209 $this->server->httpRequest = $request; 210 $this->server->exec(); 211 212 $this->assertEquals('application/xml; charset=utf-8', $this->response->getHeader('Content-Type')); 213 214 $this->assertEquals(423, $this->response->getStatus(), 'We received an incorrect status code. Full response body: ' . $this->response->getBody()); 215 216 } 217 218 /** 219 * @depends testLock 220 */ 221 function testLockNoFile() { 222 223 $request = new HTTP\Request('LOCK', '/notfound.txt'); 224 $request->setBody('<?xml version="1.0"?> 225<D:lockinfo xmlns:D="DAV:"> 226 <D:lockscope><D:exclusive/></D:lockscope> 227 <D:locktype><D:write/></D:locktype> 228 <D:owner> 229 <D:href>http://example.org/~ejw/contact.html</D:href> 230 </D:owner> 231</D:lockinfo>'); 232 233 $this->server->httpRequest = $request; 234 $this->server->exec(); 235 236 $this->assertEquals('application/xml; charset=utf-8', $this->response->getHeader('Content-Type')); 237 $this->assertTrue(preg_match('/^<opaquelocktoken:(.*)>$/', $this->response->getHeader('Lock-Token')) === 1, 'We did not get a valid Locktoken back (' . $this->response->getHeader('Lock-Token') . ')'); 238 239 $this->assertEquals(201, $this->response->status); 240 241 } 242 243 /** 244 * @depends testLock 245 */ 246 function testUnlockNoToken() { 247 248 $request = new HTTP\Request('UNLOCK', '/test.txt'); 249 $this->server->httpRequest = $request; 250 $this->server->exec(); 251 252 $this->assertEquals([ 253 'X-Sabre-Version' => [DAV\Version::VERSION], 254 'Content-Type' => ['application/xml; charset=utf-8'], 255 ], 256 $this->response->getHeaders() 257 ); 258 259 $this->assertEquals(400, $this->response->status); 260 261 } 262 263 /** 264 * @depends testLock 265 */ 266 function testUnlockBadToken() { 267 268 $request = new HTTP\Request('UNLOCK', '/test.txt', ['Lock-Token' => '<opaquelocktoken:blablabla>']); 269 $this->server->httpRequest = $request; 270 $this->server->exec(); 271 272 $this->assertEquals([ 273 'X-Sabre-Version' => [DAV\Version::VERSION], 274 'Content-Type' => ['application/xml; charset=utf-8'], 275 ], 276 $this->response->getHeaders() 277 ); 278 279 $this->assertEquals(409, $this->response->status, 'Got an incorrect status code. Full response body: ' . $this->response->body); 280 281 } 282 283 /** 284 * @depends testLock 285 */ 286 function testLockPutNoToken() { 287 288 $request = new HTTP\Request('LOCK', '/test.txt'); 289 $request->setBody('<?xml version="1.0"?> 290<D:lockinfo xmlns:D="DAV:"> 291 <D:lockscope><D:exclusive/></D:lockscope> 292 <D:locktype><D:write/></D:locktype> 293 <D:owner> 294 <D:href>http://example.org/~ejw/contact.html</D:href> 295 </D:owner> 296</D:lockinfo>'); 297 298 $this->server->httpRequest = $request; 299 $this->server->exec(); 300 301 $this->assertEquals('application/xml; charset=utf-8', $this->response->getHeader('Content-Type')); 302 $this->assertTrue(preg_match('/^<opaquelocktoken:(.*)>$/', $this->response->getHeader('Lock-Token')) === 1, 'We did not get a valid Locktoken back (' . $this->response->getHeader('Lock-Token') . ')'); 303 304 $this->assertEquals(200, $this->response->status); 305 306 $request = new HTTP\Request('PUT', '/test.txt'); 307 $request->setBody('newbody'); 308 $this->server->httpRequest = $request; 309 $this->server->exec(); 310 311 $this->assertEquals('application/xml; charset=utf-8', $this->response->getHeader('Content-Type')); 312 $this->assertTrue(preg_match('/^<opaquelocktoken:(.*)>$/', $this->response->getHeader('Lock-Token')) === 1, 'We did not get a valid Locktoken back (' . $this->response->getHeader('Lock-Token') . ')'); 313 314 $this->assertEquals(423, $this->response->status); 315 316 } 317 318 /** 319 * @depends testLock 320 */ 321 function testUnlock() { 322 323 $request = new HTTP\Request('LOCK', '/test.txt'); 324 $this->server->httpRequest = $request; 325 326 $request->setBody('<?xml version="1.0"?> 327<D:lockinfo xmlns:D="DAV:"> 328 <D:lockscope><D:exclusive/></D:lockscope> 329 <D:locktype><D:write/></D:locktype> 330 <D:owner> 331 <D:href>http://example.org/~ejw/contact.html</D:href> 332 </D:owner> 333</D:lockinfo>'); 334 335 $this->server->invokeMethod($request, $this->server->httpResponse); 336 $lockToken = $this->server->httpResponse->getHeader('Lock-Token'); 337 338 $request = new HTTP\Request('UNLOCK', '/test.txt', ['Lock-Token' => $lockToken]); 339 $this->server->httpRequest = $request; 340 $this->server->httpResponse = new HTTP\ResponseMock(); 341 $this->server->invokeMethod($request, $this->server->httpResponse); 342 343 $this->assertEquals(204, $this->server->httpResponse->status, 'Got an incorrect status code. Full response body: ' . $this->response->body); 344 $this->assertEquals([ 345 'X-Sabre-Version' => [DAV\Version::VERSION], 346 'Content-Length' => ['0'], 347 ], 348 $this->server->httpResponse->getHeaders() 349 ); 350 351 352 } 353 354 /** 355 * @depends testLock 356 */ 357 function testUnlockWindowsBug() { 358 359 $request = new HTTP\Request('LOCK', '/test.txt'); 360 $this->server->httpRequest = $request; 361 362 $request->setBody('<?xml version="1.0"?> 363<D:lockinfo xmlns:D="DAV:"> 364 <D:lockscope><D:exclusive/></D:lockscope> 365 <D:locktype><D:write/></D:locktype> 366 <D:owner> 367 <D:href>http://example.org/~ejw/contact.html</D:href> 368 </D:owner> 369</D:lockinfo>'); 370 371 $this->server->invokeMethod($request, $this->server->httpResponse); 372 $lockToken = $this->server->httpResponse->getHeader('Lock-Token'); 373 374 // See Issue 123 375 $lockToken = trim($lockToken, '<>'); 376 377 $request = new HTTP\Request('UNLOCK', '/test.txt', ['Lock-Token' => $lockToken]); 378 $this->server->httpRequest = $request; 379 $this->server->httpResponse = new HTTP\ResponseMock(); 380 $this->server->invokeMethod($request, $this->server->httpResponse); 381 382 $this->assertEquals(204, $this->server->httpResponse->status, 'Got an incorrect status code. Full response body: ' . $this->response->body); 383 $this->assertEquals([ 384 'X-Sabre-Version' => [DAV\Version::VERSION], 385 'Content-Length' => ['0'], 386 ], 387 $this->server->httpResponse->getHeaders() 388 ); 389 390 391 } 392 393 /** 394 * @depends testLock 395 */ 396 function testLockRetainOwner() { 397 398 $request = HTTP\Sapi::createFromServerArray([ 399 'REQUEST_URI' => '/test.txt', 400 'REQUEST_METHOD' => 'LOCK', 401 ]); 402 $this->server->httpRequest = $request; 403 404 $request->setBody('<?xml version="1.0"?> 405<D:lockinfo xmlns:D="DAV:"> 406 <D:lockscope><D:exclusive/></D:lockscope> 407 <D:locktype><D:write/></D:locktype> 408 <D:owner>Evert</D:owner> 409</D:lockinfo>'); 410 411 $this->server->invokeMethod($request, $this->server->httpResponse); 412 $lockToken = $this->server->httpResponse->getHeader('Lock-Token'); 413 414 $locks = $this->locksPlugin->getLocks('test.txt'); 415 $this->assertEquals(1, count($locks)); 416 $this->assertEquals('Evert', $locks[0]->owner); 417 418 419 } 420 421 /** 422 * @depends testLock 423 */ 424 function testLockPutBadToken() { 425 426 $serverVars = [ 427 'REQUEST_URI' => '/test.txt', 428 'REQUEST_METHOD' => 'LOCK', 429 ]; 430 431 $request = HTTP\Sapi::createFromServerArray($serverVars); 432 $request->setBody('<?xml version="1.0"?> 433<D:lockinfo xmlns:D="DAV:"> 434 <D:lockscope><D:exclusive/></D:lockscope> 435 <D:locktype><D:write/></D:locktype> 436 <D:owner> 437 <D:href>http://example.org/~ejw/contact.html</D:href> 438 </D:owner> 439</D:lockinfo>'); 440 441 $this->server->httpRequest = $request; 442 $this->server->exec(); 443 444 $this->assertEquals('application/xml; charset=utf-8', $this->response->getHeader('Content-Type')); 445 $this->assertTrue(preg_match('/^<opaquelocktoken:(.*)>$/', $this->response->getHeader('Lock-Token')) === 1, 'We did not get a valid Locktoken back (' . $this->response->getHeader('Lock-Token') . ')'); 446 447 $this->assertEquals(200, $this->response->status); 448 449 $serverVars = [ 450 'REQUEST_URI' => '/test.txt', 451 'REQUEST_METHOD' => 'PUT', 452 'HTTP_IF' => '(<opaquelocktoken:token1>)', 453 ]; 454 455 $request = HTTP\Sapi::createFromServerArray($serverVars); 456 $request->setBody('newbody'); 457 $this->server->httpRequest = $request; 458 $this->server->exec(); 459 460 $this->assertEquals('application/xml; charset=utf-8', $this->response->getHeader('Content-Type')); 461 $this->assertTrue(preg_match('/^<opaquelocktoken:(.*)>$/', $this->response->getHeader('Lock-Token')) === 1, 'We did not get a valid Locktoken back (' . $this->response->getHeader('Lock-Token') . ')'); 462 463 // $this->assertEquals('412 Precondition failed',$this->response->status); 464 $this->assertEquals(423, $this->response->status); 465 466 } 467 468 /** 469 * @depends testLock 470 */ 471 function testLockDeleteParent() { 472 473 $serverVars = [ 474 'REQUEST_URI' => '/dir/child.txt', 475 'REQUEST_METHOD' => 'LOCK', 476 ]; 477 478 $request = HTTP\Sapi::createFromServerArray($serverVars); 479 $request->setBody('<?xml version="1.0"?> 480<D:lockinfo xmlns:D="DAV:"> 481 <D:lockscope><D:exclusive/></D:lockscope> 482 <D:locktype><D:write/></D:locktype> 483 <D:owner> 484 <D:href>http://example.org/~ejw/contact.html</D:href> 485 </D:owner> 486</D:lockinfo>'); 487 488 $this->server->httpRequest = $request; 489 $this->server->exec(); 490 491 $this->assertEquals('application/xml; charset=utf-8', $this->response->getHeader('Content-Type')); 492 $this->assertTrue(preg_match('/^<opaquelocktoken:(.*)>$/', $this->response->getHeader('Lock-Token')) === 1, 'We did not get a valid Locktoken back (' . $this->response->getHeader('Lock-Token') . ')'); 493 494 $this->assertEquals(200, $this->response->status); 495 496 $serverVars = [ 497 'REQUEST_URI' => '/dir', 498 'REQUEST_METHOD' => 'DELETE', 499 ]; 500 501 $request = HTTP\Sapi::createFromServerArray($serverVars); 502 $this->server->httpRequest = $request; 503 $this->server->exec(); 504 505 $this->assertEquals(423, $this->response->status); 506 $this->assertEquals('application/xml; charset=utf-8', $this->response->getHeader('Content-Type')); 507 508 } 509 /** 510 * @depends testLock 511 */ 512 function testLockDeleteSucceed() { 513 514 $serverVars = [ 515 'REQUEST_URI' => '/dir/child.txt', 516 'REQUEST_METHOD' => 'LOCK', 517 ]; 518 519 $request = HTTP\Sapi::createFromServerArray($serverVars); 520 $request->setBody('<?xml version="1.0"?> 521<D:lockinfo xmlns:D="DAV:"> 522 <D:lockscope><D:exclusive/></D:lockscope> 523 <D:locktype><D:write/></D:locktype> 524 <D:owner> 525 <D:href>http://example.org/~ejw/contact.html</D:href> 526 </D:owner> 527</D:lockinfo>'); 528 529 $this->server->httpRequest = $request; 530 $this->server->exec(); 531 532 $this->assertEquals('application/xml; charset=utf-8', $this->response->getHeader('Content-Type')); 533 $this->assertTrue(preg_match('/^<opaquelocktoken:(.*)>$/', $this->response->getHeader('Lock-Token')) === 1, 'We did not get a valid Locktoken back (' . $this->response->getHeader('Lock-Token') . ')'); 534 535 $this->assertEquals(200, $this->response->status); 536 537 $serverVars = [ 538 'REQUEST_URI' => '/dir/child.txt', 539 'REQUEST_METHOD' => 'DELETE', 540 'HTTP_IF' => '(' . $this->response->getHeader('Lock-Token') . ')', 541 ]; 542 543 $request = HTTP\Sapi::createFromServerArray($serverVars); 544 $this->server->httpRequest = $request; 545 $this->server->exec(); 546 547 $this->assertEquals(204, $this->response->status); 548 $this->assertEquals('application/xml; charset=utf-8', $this->response->getHeader('Content-Type')); 549 550 } 551 552 /** 553 * @depends testLock 554 */ 555 function testLockCopyLockSource() { 556 557 $serverVars = [ 558 'REQUEST_URI' => '/dir/child.txt', 559 'REQUEST_METHOD' => 'LOCK', 560 ]; 561 562 $request = HTTP\Sapi::createFromServerArray($serverVars); 563 $request->setBody('<?xml version="1.0"?> 564<D:lockinfo xmlns:D="DAV:"> 565 <D:lockscope><D:exclusive/></D:lockscope> 566 <D:locktype><D:write/></D:locktype> 567 <D:owner> 568 <D:href>http://example.org/~ejw/contact.html</D:href> 569 </D:owner> 570</D:lockinfo>'); 571 572 $this->server->httpRequest = $request; 573 $this->server->exec(); 574 575 $this->assertEquals('application/xml; charset=utf-8', $this->response->getHeader('Content-Type')); 576 $this->assertTrue(preg_match('/^<opaquelocktoken:(.*)>$/', $this->response->getHeader('Lock-Token')) === 1, 'We did not get a valid Locktoken back (' . $this->response->getHeader('Lock-Token') . ')'); 577 578 $this->assertEquals(200, $this->response->status); 579 580 $serverVars = [ 581 'REQUEST_URI' => '/dir/child.txt', 582 'REQUEST_METHOD' => 'COPY', 583 'HTTP_DESTINATION' => '/dir/child2.txt', 584 ]; 585 586 $request = HTTP\Sapi::createFromServerArray($serverVars); 587 $this->server->httpRequest = $request; 588 $this->server->exec(); 589 590 $this->assertEquals(201, $this->response->status, 'Copy must succeed if only the source is locked, but not the destination'); 591 $this->assertEquals('application/xml; charset=utf-8', $this->response->getHeader('Content-Type')); 592 593 } 594 /** 595 * @depends testLock 596 */ 597 function testLockCopyLockDestination() { 598 599 $serverVars = [ 600 'REQUEST_URI' => '/dir/child2.txt', 601 'REQUEST_METHOD' => 'LOCK', 602 ]; 603 604 $request = HTTP\Sapi::createFromServerArray($serverVars); 605 $request->setBody('<?xml version="1.0"?> 606<D:lockinfo xmlns:D="DAV:"> 607 <D:lockscope><D:exclusive/></D:lockscope> 608 <D:locktype><D:write/></D:locktype> 609 <D:owner> 610 <D:href>http://example.org/~ejw/contact.html</D:href> 611 </D:owner> 612</D:lockinfo>'); 613 614 $this->server->httpRequest = $request; 615 $this->server->exec(); 616 617 $this->assertEquals('application/xml; charset=utf-8', $this->response->getHeader('Content-Type')); 618 $this->assertTrue(preg_match('/^<opaquelocktoken:(.*)>$/', $this->response->getHeader('Lock-Token')) === 1, 'We did not get a valid Locktoken back (' . $this->response->getHeader('Lock-Token') . ')'); 619 620 $this->assertEquals(201, $this->response->status); 621 622 $serverVars = [ 623 'REQUEST_URI' => '/dir/child.txt', 624 'REQUEST_METHOD' => 'COPY', 625 'HTTP_DESTINATION' => '/dir/child2.txt', 626 ]; 627 628 $request = HTTP\Sapi::createFromServerArray($serverVars); 629 $this->server->httpRequest = $request; 630 $this->server->exec(); 631 632 $this->assertEquals(423, $this->response->status, 'Copy must succeed if only the source is locked, but not the destination'); 633 $this->assertEquals('application/xml; charset=utf-8', $this->response->getHeader('Content-Type')); 634 635 } 636 637 /** 638 * @depends testLock 639 */ 640 function testLockMoveLockSourceLocked() { 641 642 $serverVars = [ 643 'REQUEST_URI' => '/dir/child.txt', 644 'REQUEST_METHOD' => 'LOCK', 645 ]; 646 647 $request = HTTP\Sapi::createFromServerArray($serverVars); 648 $request->setBody('<?xml version="1.0"?> 649<D:lockinfo xmlns:D="DAV:"> 650 <D:lockscope><D:exclusive/></D:lockscope> 651 <D:locktype><D:write/></D:locktype> 652 <D:owner> 653 <D:href>http://example.org/~ejw/contact.html</D:href> 654 </D:owner> 655</D:lockinfo>'); 656 657 $this->server->httpRequest = $request; 658 $this->server->exec(); 659 660 $this->assertEquals('application/xml; charset=utf-8', $this->response->getHeader('Content-Type')); 661 $this->assertTrue(preg_match('/^<opaquelocktoken:(.*)>$/', $this->response->getHeader('Lock-Token')) === 1, 'We did not get a valid Locktoken back (' . $this->response->getHeader('Lock-Token') . ')'); 662 663 $this->assertEquals(200, $this->response->status); 664 665 $serverVars = [ 666 'REQUEST_URI' => '/dir/child.txt', 667 'REQUEST_METHOD' => 'MOVE', 668 'HTTP_DESTINATION' => '/dir/child2.txt', 669 ]; 670 671 $request = HTTP\Sapi::createFromServerArray($serverVars); 672 $this->server->httpRequest = $request; 673 $this->server->exec(); 674 675 $this->assertEquals(423, $this->response->status, 'Copy must succeed if only the source is locked, but not the destination'); 676 $this->assertEquals('application/xml; charset=utf-8', $this->response->getHeader('Content-Type')); 677 678 } 679 680 /** 681 * @depends testLock 682 */ 683 function testLockMoveLockSourceSucceed() { 684 685 $serverVars = [ 686 'REQUEST_URI' => '/dir/child.txt', 687 'REQUEST_METHOD' => 'LOCK', 688 ]; 689 690 $request = HTTP\Sapi::createFromServerArray($serverVars); 691 $request->setBody('<?xml version="1.0"?> 692<D:lockinfo xmlns:D="DAV:"> 693 <D:lockscope><D:exclusive/></D:lockscope> 694 <D:locktype><D:write/></D:locktype> 695 <D:owner> 696 <D:href>http://example.org/~ejw/contact.html</D:href> 697 </D:owner> 698</D:lockinfo>'); 699 700 $this->server->httpRequest = $request; 701 $this->server->exec(); 702 703 $this->assertEquals('application/xml; charset=utf-8', $this->response->getHeader('Content-Type')); 704 $this->assertTrue(preg_match('/^<opaquelocktoken:(.*)>$/', $this->response->getHeader('Lock-Token')) === 1, 'We did not get a valid Locktoken back (' . $this->response->getHeader('Lock-Token') . ')'); 705 706 $this->assertEquals(200, $this->response->status); 707 708 $serverVars = [ 709 'REQUEST_URI' => '/dir/child.txt', 710 'REQUEST_METHOD' => 'MOVE', 711 'HTTP_DESTINATION' => '/dir/child2.txt', 712 'HTTP_IF' => '(' . $this->response->getHeader('Lock-Token') . ')', 713 ]; 714 715 $request = HTTP\Sapi::createFromServerArray($serverVars); 716 $this->server->httpRequest = $request; 717 $this->server->exec(); 718 719 $this->assertEquals(201, $this->response->status, 'A valid lock-token was provided for the source, so this MOVE operation must succeed. Full response body: ' . $this->response->body); 720 721 } 722 723 /** 724 * @depends testLock 725 */ 726 function testLockMoveLockDestination() { 727 728 $serverVars = [ 729 'REQUEST_URI' => '/dir/child2.txt', 730 'REQUEST_METHOD' => 'LOCK', 731 ]; 732 733 $request = HTTP\Sapi::createFromServerArray($serverVars); 734 $request->setBody('<?xml version="1.0"?> 735<D:lockinfo xmlns:D="DAV:"> 736 <D:lockscope><D:exclusive/></D:lockscope> 737 <D:locktype><D:write/></D:locktype> 738 <D:owner> 739 <D:href>http://example.org/~ejw/contact.html</D:href> 740 </D:owner> 741</D:lockinfo>'); 742 743 $this->server->httpRequest = $request; 744 $this->server->exec(); 745 746 $this->assertEquals('application/xml; charset=utf-8', $this->response->getHeader('Content-Type')); 747 $this->assertTrue(preg_match('/^<opaquelocktoken:(.*)>$/', $this->response->getHeader('Lock-Token')) === 1, 'We did not get a valid Locktoken back (' . $this->response->getHeader('Lock-Token') . ')'); 748 749 $this->assertEquals(201, $this->response->status); 750 751 $serverVars = [ 752 'REQUEST_URI' => '/dir/child.txt', 753 'REQUEST_METHOD' => 'MOVE', 754 'HTTP_DESTINATION' => '/dir/child2.txt', 755 ]; 756 757 $request = HTTP\Sapi::createFromServerArray($serverVars); 758 $this->server->httpRequest = $request; 759 $this->server->exec(); 760 761 $this->assertEquals(423, $this->response->status, 'Copy must succeed if only the source is locked, but not the destination'); 762 $this->assertEquals('application/xml; charset=utf-8', $this->response->getHeader('Content-Type')); 763 764 } 765 /** 766 * @depends testLock 767 */ 768 function testLockMoveLockParent() { 769 770 $serverVars = [ 771 'REQUEST_URI' => '/dir', 772 'REQUEST_METHOD' => 'LOCK', 773 'HTTP_DEPTH' => 'infinite', 774 ]; 775 776 $request = HTTP\Sapi::createFromServerArray($serverVars); 777 $request->setBody('<?xml version="1.0"?> 778<D:lockinfo xmlns:D="DAV:"> 779 <D:lockscope><D:exclusive/></D:lockscope> 780 <D:locktype><D:write/></D:locktype> 781 <D:owner> 782 <D:href>http://example.org/~ejw/contact.html</D:href> 783 </D:owner> 784</D:lockinfo>'); 785 786 $this->server->httpRequest = $request; 787 $this->server->exec(); 788 789 $this->assertEquals('application/xml; charset=utf-8', $this->response->getHeader('Content-Type')); 790 $this->assertTrue(preg_match('/^<opaquelocktoken:(.*)>$/', $this->response->getHeader('Lock-Token')) === 1, 'We did not get a valid Locktoken back (' . $this->response->getHeader('Lock-Token') . ')'); 791 792 $this->assertEquals(200, $this->response->status); 793 794 $serverVars = [ 795 'REQUEST_URI' => '/dir/child.txt', 796 'REQUEST_METHOD' => 'MOVE', 797 'HTTP_DESTINATION' => '/dir/child2.txt', 798 'HTTP_IF' => '</dir> (' . $this->response->getHeader('Lock-Token') . ')', 799 ]; 800 801 $request = HTTP\Sapi::createFromServerArray($serverVars); 802 $this->server->httpRequest = $request; 803 $this->server->exec(); 804 805 $this->assertEquals(201, $this->response->status, 'We locked the parent of both the source and destination, but the move didn\'t succeed.'); 806 $this->assertEquals('application/xml; charset=utf-8', $this->response->getHeader('Content-Type')); 807 808 } 809 810 /** 811 * @depends testLock 812 */ 813 function testLockPutGoodToken() { 814 815 $serverVars = [ 816 'REQUEST_URI' => '/test.txt', 817 'REQUEST_METHOD' => 'LOCK', 818 ]; 819 820 $request = HTTP\Sapi::createFromServerArray($serverVars); 821 $request->setBody('<?xml version="1.0"?> 822<D:lockinfo xmlns:D="DAV:"> 823 <D:lockscope><D:exclusive/></D:lockscope> 824 <D:locktype><D:write/></D:locktype> 825 <D:owner> 826 <D:href>http://example.org/~ejw/contact.html</D:href> 827 </D:owner> 828</D:lockinfo>'); 829 830 $this->server->httpRequest = $request; 831 $this->server->exec(); 832 833 $this->assertEquals('application/xml; charset=utf-8', $this->response->getHeader('Content-Type')); 834 $this->assertTrue(preg_match('/^<opaquelocktoken:(.*)>$/', $this->response->getHeader('Lock-Token')) === 1, 'We did not get a valid Locktoken back (' . $this->response->getHeader('Lock-Token') . ')'); 835 836 $this->assertEquals(200, $this->response->status); 837 838 $serverVars = [ 839 'REQUEST_URI' => '/test.txt', 840 'REQUEST_METHOD' => 'PUT', 841 'HTTP_IF' => '(' . $this->response->getHeader('Lock-Token') . ')', 842 ]; 843 844 $request = HTTP\Sapi::createFromServerArray($serverVars); 845 $request->setBody('newbody'); 846 $this->server->httpRequest = $request; 847 $this->server->exec(); 848 849 $this->assertEquals('application/xml; charset=utf-8', $this->response->getHeader('Content-Type')); 850 $this->assertTrue(preg_match('/^<opaquelocktoken:(.*)>$/', $this->response->getHeader('Lock-Token')) === 1, 'We did not get a valid Locktoken back (' . $this->response->getHeader('Lock-Token') . ')'); 851 852 $this->assertEquals(204, $this->response->status); 853 854 } 855 856 /** 857 * @depends testLock 858 */ 859 function testLockPutUnrelatedToken() { 860 861 $request = new HTTP\Request('LOCK', '/unrelated.txt'); 862 $request->setBody('<?xml version="1.0"?> 863<D:lockinfo xmlns:D="DAV:"> 864 <D:lockscope><D:exclusive/></D:lockscope> 865 <D:locktype><D:write/></D:locktype> 866 <D:owner> 867 <D:href>http://example.org/~ejw/contact.html</D:href> 868 </D:owner> 869</D:lockinfo>'); 870 871 $this->server->httpRequest = $request; 872 $this->server->exec(); 873 874 $this->assertEquals('application/xml; charset=utf-8', $this->response->getHeader('Content-Type')); 875 $this->assertTrue(preg_match('/^<opaquelocktoken:(.*)>$/', $this->response->getHeader('Lock-Token')) === 1, 'We did not get a valid Locktoken back (' . $this->response->getHeader('Lock-Token') . ')'); 876 877 $this->assertEquals(201, $this->response->getStatus()); 878 879 $request = new HTTP\Request( 880 'PUT', 881 '/test.txt', 882 ['If' => '</unrelated.txt> (' . $this->response->getHeader('Lock-Token') . ')'] 883 ); 884 $request->setBody('newbody'); 885 $this->server->httpRequest = $request; 886 $this->server->exec(); 887 888 $this->assertEquals('application/xml; charset=utf-8', $this->response->getHeader('Content-Type')); 889 $this->assertTrue(preg_match('/^<opaquelocktoken:(.*)>$/', $this->response->getHeader('Lock-Token')) === 1, 'We did not get a valid Locktoken back (' . $this->response->getHeader('Lock-Token') . ')'); 890 891 $this->assertEquals(204, $this->response->status); 892 893 } 894 895 function testPutWithIncorrectETag() { 896 897 $serverVars = [ 898 'REQUEST_URI' => '/test.txt', 899 'REQUEST_METHOD' => 'PUT', 900 'HTTP_IF' => '(["etag1"])', 901 ]; 902 903 $request = HTTP\Sapi::createFromServerArray($serverVars); 904 $request->setBody('newbody'); 905 $this->server->httpRequest = $request; 906 $this->server->exec(); 907 $this->assertEquals(412, $this->response->status); 908 909 } 910 911 /** 912 * @depends testPutWithIncorrectETag 913 */ 914 function testPutWithCorrectETag() { 915 916 // We need an ETag-enabled file node. 917 $tree = new DAV\Tree(new DAV\FSExt\Directory(SABRE_TEMPDIR)); 918 $this->server->tree = $tree; 919 920 $filename = SABRE_TEMPDIR . '/test.txt'; 921 $etag = sha1( 922 fileinode($filename) . 923 filesize($filename) . 924 filemtime($filename) 925 ); 926 $serverVars = [ 927 'REQUEST_URI' => '/test.txt', 928 'REQUEST_METHOD' => 'PUT', 929 'HTTP_IF' => '(["' . $etag . '"])', 930 ]; 931 932 $request = HTTP\Sapi::createFromServerArray($serverVars); 933 $request->setBody('newbody'); 934 $this->server->httpRequest = $request; 935 $this->server->exec(); 936 $this->assertEquals(204, $this->response->status, 'Incorrect status received. Full response body:' . $this->response->body); 937 938 } 939 940 function testDeleteWithETagOnCollection() { 941 942 $serverVars = [ 943 'REQUEST_URI' => '/dir', 944 'REQUEST_METHOD' => 'DELETE', 945 'HTTP_IF' => '(["etag1"])', 946 ]; 947 $request = HTTP\Sapi::createFromServerArray($serverVars); 948 949 $this->server->httpRequest = $request; 950 $this->server->exec(); 951 $this->assertEquals(412, $this->response->status); 952 953 } 954 955 function testGetTimeoutHeader() { 956 957 $request = HTTP\Sapi::createFromServerArray([ 958 'HTTP_TIMEOUT' => 'second-100', 959 ]); 960 961 $this->server->httpRequest = $request; 962 $this->assertEquals(100, $this->locksPlugin->getTimeoutHeader()); 963 964 } 965 966 function testGetTimeoutHeaderTwoItems() { 967 968 $request = HTTP\Sapi::createFromServerArray([ 969 'HTTP_TIMEOUT' => 'second-5, infinite', 970 ]); 971 972 $this->server->httpRequest = $request; 973 $this->assertEquals(5, $this->locksPlugin->getTimeoutHeader()); 974 975 } 976 977 function testGetTimeoutHeaderInfinite() { 978 979 $request = HTTP\Sapi::createFromServerArray([ 980 'HTTP_TIMEOUT' => 'infinite, second-5', 981 ]); 982 983 $this->server->httpRequest = $request; 984 $this->assertEquals(LockInfo::TIMEOUT_INFINITE, $this->locksPlugin->getTimeoutHeader()); 985 986 } 987 988 /** 989 * @expectedException Sabre\DAV\Exception\BadRequest 990 */ 991 function testGetTimeoutHeaderInvalid() { 992 993 $request = HTTP\Sapi::createFromServerArray([ 994 'HTTP_TIMEOUT' => 'yourmom', 995 ]); 996 997 $this->server->httpRequest = $request; 998 $this->locksPlugin->getTimeoutHeader(); 999 1000 } 1001 1002 1003} 1004