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