1*a1a3b679SAndreas Boehler<?php 2*a1a3b679SAndreas Boehler 3*a1a3b679SAndreas Boehlernamespace Sabre\DAV; 4*a1a3b679SAndreas Boehler 5*a1a3b679SAndreas Boehleruse Sabre\DAVServerTest; 6*a1a3b679SAndreas Boehleruse Sabre\HTTP; 7*a1a3b679SAndreas Boehler 8*a1a3b679SAndreas Boehler/** 9*a1a3b679SAndreas Boehler * Tests related to the PUT request. 10*a1a3b679SAndreas Boehler * 11*a1a3b679SAndreas Boehler * @copyright Copyright (C) 2007-2015 fruux GmbH (https://fruux.com/). 12*a1a3b679SAndreas Boehler * @author Evert Pot (http://evertpot.com/) 13*a1a3b679SAndreas Boehler * @license http://sabre.io/license/ Modified BSD License 14*a1a3b679SAndreas Boehler */ 15*a1a3b679SAndreas Boehlerclass HttpPutTest extends DAVServerTest { 16*a1a3b679SAndreas Boehler 17*a1a3b679SAndreas Boehler /** 18*a1a3b679SAndreas Boehler * Sets up the DAV tree. 19*a1a3b679SAndreas Boehler * 20*a1a3b679SAndreas Boehler * @return void 21*a1a3b679SAndreas Boehler */ 22*a1a3b679SAndreas Boehler function setUpTree() { 23*a1a3b679SAndreas Boehler 24*a1a3b679SAndreas Boehler $this->tree = new Mock\Collection('root', [ 25*a1a3b679SAndreas Boehler 'file1' => 'foo', 26*a1a3b679SAndreas Boehler ]); 27*a1a3b679SAndreas Boehler 28*a1a3b679SAndreas Boehler } 29*a1a3b679SAndreas Boehler 30*a1a3b679SAndreas Boehler /** 31*a1a3b679SAndreas Boehler * A successful PUT of a new file. 32*a1a3b679SAndreas Boehler */ 33*a1a3b679SAndreas Boehler function testPut() { 34*a1a3b679SAndreas Boehler 35*a1a3b679SAndreas Boehler $request = new HTTP\Request('PUT', '/file2', [], 'hello'); 36*a1a3b679SAndreas Boehler 37*a1a3b679SAndreas Boehler $response = $this->request($request); 38*a1a3b679SAndreas Boehler 39*a1a3b679SAndreas Boehler $this->assertEquals(201, $response->getStatus(), 'Incorrect status code received. Full response body:' . $response->getBodyAsString()); 40*a1a3b679SAndreas Boehler 41*a1a3b679SAndreas Boehler $this->assertEquals( 42*a1a3b679SAndreas Boehler 'hello', 43*a1a3b679SAndreas Boehler $this->server->tree->getNodeForPath('file2')->get() 44*a1a3b679SAndreas Boehler ); 45*a1a3b679SAndreas Boehler 46*a1a3b679SAndreas Boehler $this->assertEquals( 47*a1a3b679SAndreas Boehler [ 48*a1a3b679SAndreas Boehler 'X-Sabre-Version' => [Version::VERSION], 49*a1a3b679SAndreas Boehler 'Content-Length' => ['0'], 50*a1a3b679SAndreas Boehler 'ETag' => ['"' . md5('hello') . '"'] 51*a1a3b679SAndreas Boehler ], 52*a1a3b679SAndreas Boehler $response->getHeaders() 53*a1a3b679SAndreas Boehler ); 54*a1a3b679SAndreas Boehler 55*a1a3b679SAndreas Boehler } 56*a1a3b679SAndreas Boehler 57*a1a3b679SAndreas Boehler /** 58*a1a3b679SAndreas Boehler * A successful PUT on an existing file. 59*a1a3b679SAndreas Boehler * 60*a1a3b679SAndreas Boehler * @depends testPut 61*a1a3b679SAndreas Boehler */ 62*a1a3b679SAndreas Boehler function testPutExisting() { 63*a1a3b679SAndreas Boehler 64*a1a3b679SAndreas Boehler $request = new HTTP\Request('PUT', '/file1', [], 'bar'); 65*a1a3b679SAndreas Boehler 66*a1a3b679SAndreas Boehler $response = $this->request($request); 67*a1a3b679SAndreas Boehler 68*a1a3b679SAndreas Boehler $this->assertEquals(204, $response->getStatus()); 69*a1a3b679SAndreas Boehler 70*a1a3b679SAndreas Boehler $this->assertEquals( 71*a1a3b679SAndreas Boehler 'bar', 72*a1a3b679SAndreas Boehler $this->server->tree->getNodeForPath('file1')->get() 73*a1a3b679SAndreas Boehler ); 74*a1a3b679SAndreas Boehler 75*a1a3b679SAndreas Boehler $this->assertEquals( 76*a1a3b679SAndreas Boehler [ 77*a1a3b679SAndreas Boehler 'X-Sabre-Version' => [Version::VERSION], 78*a1a3b679SAndreas Boehler 'Content-Length' => ['0'], 79*a1a3b679SAndreas Boehler 'ETag' => ['"' . md5('bar') . '"'] 80*a1a3b679SAndreas Boehler ], 81*a1a3b679SAndreas Boehler $response->getHeaders() 82*a1a3b679SAndreas Boehler ); 83*a1a3b679SAndreas Boehler 84*a1a3b679SAndreas Boehler } 85*a1a3b679SAndreas Boehler 86*a1a3b679SAndreas Boehler /** 87*a1a3b679SAndreas Boehler * PUT on existing file with If-Match: * 88*a1a3b679SAndreas Boehler * 89*a1a3b679SAndreas Boehler * @depends testPutExisting 90*a1a3b679SAndreas Boehler */ 91*a1a3b679SAndreas Boehler function testPutExistingIfMatchStar() { 92*a1a3b679SAndreas Boehler 93*a1a3b679SAndreas Boehler $request = new HTTP\Request( 94*a1a3b679SAndreas Boehler 'PUT', 95*a1a3b679SAndreas Boehler '/file1', 96*a1a3b679SAndreas Boehler ['If-Match' => '*'], 97*a1a3b679SAndreas Boehler 'hello' 98*a1a3b679SAndreas Boehler ); 99*a1a3b679SAndreas Boehler 100*a1a3b679SAndreas Boehler $response = $this->request($request); 101*a1a3b679SAndreas Boehler 102*a1a3b679SAndreas Boehler $this->assertEquals(204, $response->getStatus()); 103*a1a3b679SAndreas Boehler 104*a1a3b679SAndreas Boehler $this->assertEquals( 105*a1a3b679SAndreas Boehler 'hello', 106*a1a3b679SAndreas Boehler $this->server->tree->getNodeForPath('file1')->get() 107*a1a3b679SAndreas Boehler ); 108*a1a3b679SAndreas Boehler 109*a1a3b679SAndreas Boehler $this->assertEquals( 110*a1a3b679SAndreas Boehler [ 111*a1a3b679SAndreas Boehler 'X-Sabre-Version' => [Version::VERSION], 112*a1a3b679SAndreas Boehler 'Content-Length' => ['0'], 113*a1a3b679SAndreas Boehler 'ETag' => ['"' . md5('hello') . '"'] 114*a1a3b679SAndreas Boehler ], 115*a1a3b679SAndreas Boehler $response->getHeaders() 116*a1a3b679SAndreas Boehler ); 117*a1a3b679SAndreas Boehler 118*a1a3b679SAndreas Boehler } 119*a1a3b679SAndreas Boehler 120*a1a3b679SAndreas Boehler /** 121*a1a3b679SAndreas Boehler * PUT on existing file with If-Match: with a correct etag 122*a1a3b679SAndreas Boehler * 123*a1a3b679SAndreas Boehler * @depends testPutExisting 124*a1a3b679SAndreas Boehler */ 125*a1a3b679SAndreas Boehler function testPutExistingIfMatchCorrect() { 126*a1a3b679SAndreas Boehler 127*a1a3b679SAndreas Boehler $request = new HTTP\Request( 128*a1a3b679SAndreas Boehler 'PUT', 129*a1a3b679SAndreas Boehler '/file1', 130*a1a3b679SAndreas Boehler ['If-Match' => '"' . md5('foo') . '"'], 131*a1a3b679SAndreas Boehler 'hello' 132*a1a3b679SAndreas Boehler ); 133*a1a3b679SAndreas Boehler 134*a1a3b679SAndreas Boehler $response = $this->request($request); 135*a1a3b679SAndreas Boehler 136*a1a3b679SAndreas Boehler $this->assertEquals(204, $response->status); 137*a1a3b679SAndreas Boehler 138*a1a3b679SAndreas Boehler $this->assertEquals( 139*a1a3b679SAndreas Boehler 'hello', 140*a1a3b679SAndreas Boehler $this->server->tree->getNodeForPath('file1')->get() 141*a1a3b679SAndreas Boehler ); 142*a1a3b679SAndreas Boehler 143*a1a3b679SAndreas Boehler $this->assertEquals( 144*a1a3b679SAndreas Boehler [ 145*a1a3b679SAndreas Boehler 'X-Sabre-Version' => [Version::VERSION], 146*a1a3b679SAndreas Boehler 'Content-Length' => ['0'], 147*a1a3b679SAndreas Boehler 'ETag' => ['"' . md5('hello') . '"'], 148*a1a3b679SAndreas Boehler ], 149*a1a3b679SAndreas Boehler $response->getHeaders() 150*a1a3b679SAndreas Boehler ); 151*a1a3b679SAndreas Boehler 152*a1a3b679SAndreas Boehler } 153*a1a3b679SAndreas Boehler 154*a1a3b679SAndreas Boehler /** 155*a1a3b679SAndreas Boehler * PUT with Content-Range should be rejected. 156*a1a3b679SAndreas Boehler * 157*a1a3b679SAndreas Boehler * @depends testPut 158*a1a3b679SAndreas Boehler */ 159*a1a3b679SAndreas Boehler function testPutContentRange() { 160*a1a3b679SAndreas Boehler 161*a1a3b679SAndreas Boehler $request = new HTTP\Request( 162*a1a3b679SAndreas Boehler 'PUT', 163*a1a3b679SAndreas Boehler '/file2', 164*a1a3b679SAndreas Boehler ['Content-Range' => 'bytes/100-200'], 165*a1a3b679SAndreas Boehler 'hello' 166*a1a3b679SAndreas Boehler ); 167*a1a3b679SAndreas Boehler 168*a1a3b679SAndreas Boehler $response = $this->request($request); 169*a1a3b679SAndreas Boehler $this->assertEquals(400, $response->getStatus()); 170*a1a3b679SAndreas Boehler 171*a1a3b679SAndreas Boehler } 172*a1a3b679SAndreas Boehler 173*a1a3b679SAndreas Boehler /** 174*a1a3b679SAndreas Boehler * PUT on non-existing file with If-None-Match: * should work. 175*a1a3b679SAndreas Boehler * 176*a1a3b679SAndreas Boehler * @depends testPut 177*a1a3b679SAndreas Boehler */ 178*a1a3b679SAndreas Boehler function testPutIfNoneMatchStar() { 179*a1a3b679SAndreas Boehler 180*a1a3b679SAndreas Boehler $request = new HTTP\Request( 181*a1a3b679SAndreas Boehler 'PUT', 182*a1a3b679SAndreas Boehler '/file2', 183*a1a3b679SAndreas Boehler ['If-None-Match' => '*'], 184*a1a3b679SAndreas Boehler 'hello' 185*a1a3b679SAndreas Boehler ); 186*a1a3b679SAndreas Boehler 187*a1a3b679SAndreas Boehler $response = $this->request($request); 188*a1a3b679SAndreas Boehler 189*a1a3b679SAndreas Boehler $this->assertEquals(201, $response->getStatus()); 190*a1a3b679SAndreas Boehler 191*a1a3b679SAndreas Boehler $this->assertEquals( 192*a1a3b679SAndreas Boehler 'hello', 193*a1a3b679SAndreas Boehler $this->server->tree->getNodeForPath('file2')->get() 194*a1a3b679SAndreas Boehler ); 195*a1a3b679SAndreas Boehler 196*a1a3b679SAndreas Boehler $this->assertEquals( 197*a1a3b679SAndreas Boehler [ 198*a1a3b679SAndreas Boehler 'X-Sabre-Version' => [Version::VERSION], 199*a1a3b679SAndreas Boehler 'Content-Length' => ['0'], 200*a1a3b679SAndreas Boehler 'ETag' => ['"' . md5('hello') . '"'] 201*a1a3b679SAndreas Boehler ], 202*a1a3b679SAndreas Boehler $response->getHeaders() 203*a1a3b679SAndreas Boehler ); 204*a1a3b679SAndreas Boehler 205*a1a3b679SAndreas Boehler } 206*a1a3b679SAndreas Boehler 207*a1a3b679SAndreas Boehler /** 208*a1a3b679SAndreas Boehler * PUT on non-existing file with If-Match: * should fail. 209*a1a3b679SAndreas Boehler * 210*a1a3b679SAndreas Boehler * @depends testPut 211*a1a3b679SAndreas Boehler */ 212*a1a3b679SAndreas Boehler function testPutIfMatchStar() { 213*a1a3b679SAndreas Boehler 214*a1a3b679SAndreas Boehler $request = new HTTP\Request( 215*a1a3b679SAndreas Boehler 'PUT', 216*a1a3b679SAndreas Boehler '/file2', 217*a1a3b679SAndreas Boehler ['If-Match' => '*'], 218*a1a3b679SAndreas Boehler 'hello' 219*a1a3b679SAndreas Boehler ); 220*a1a3b679SAndreas Boehler 221*a1a3b679SAndreas Boehler $response = $this->request($request); 222*a1a3b679SAndreas Boehler 223*a1a3b679SAndreas Boehler $this->assertEquals(412, $response->getStatus()); 224*a1a3b679SAndreas Boehler 225*a1a3b679SAndreas Boehler } 226*a1a3b679SAndreas Boehler 227*a1a3b679SAndreas Boehler /** 228*a1a3b679SAndreas Boehler * PUT on existing file with If-None-Match: * should fail. 229*a1a3b679SAndreas Boehler * 230*a1a3b679SAndreas Boehler * @depends testPut 231*a1a3b679SAndreas Boehler */ 232*a1a3b679SAndreas Boehler function testPutExistingIfNoneMatchStar() { 233*a1a3b679SAndreas Boehler 234*a1a3b679SAndreas Boehler $request = new HTTP\Request( 235*a1a3b679SAndreas Boehler 'PUT', 236*a1a3b679SAndreas Boehler '/file1', 237*a1a3b679SAndreas Boehler ['If-None-Match' => '*'], 238*a1a3b679SAndreas Boehler 'hello' 239*a1a3b679SAndreas Boehler ); 240*a1a3b679SAndreas Boehler $request->setBody('hello'); 241*a1a3b679SAndreas Boehler 242*a1a3b679SAndreas Boehler $response = $this->request($request); 243*a1a3b679SAndreas Boehler 244*a1a3b679SAndreas Boehler $this->assertEquals(412, $response->getStatus()); 245*a1a3b679SAndreas Boehler 246*a1a3b679SAndreas Boehler } 247*a1a3b679SAndreas Boehler 248*a1a3b679SAndreas Boehler /** 249*a1a3b679SAndreas Boehler * PUT thats created in a non-collection should be rejected. 250*a1a3b679SAndreas Boehler * 251*a1a3b679SAndreas Boehler * @depends testPut 252*a1a3b679SAndreas Boehler */ 253*a1a3b679SAndreas Boehler function testPutNoParent() { 254*a1a3b679SAndreas Boehler 255*a1a3b679SAndreas Boehler $request = new HTTP\Request( 256*a1a3b679SAndreas Boehler 'PUT', 257*a1a3b679SAndreas Boehler '/file1/file2', 258*a1a3b679SAndreas Boehler [], 259*a1a3b679SAndreas Boehler 'hello' 260*a1a3b679SAndreas Boehler ); 261*a1a3b679SAndreas Boehler 262*a1a3b679SAndreas Boehler $response = $this->request($request); 263*a1a3b679SAndreas Boehler $this->assertEquals(409, $response->getStatus()); 264*a1a3b679SAndreas Boehler 265*a1a3b679SAndreas Boehler } 266*a1a3b679SAndreas Boehler 267*a1a3b679SAndreas Boehler /** 268*a1a3b679SAndreas Boehler * Finder may sometimes make a request, which gets its content-body 269*a1a3b679SAndreas Boehler * stripped. We can't always prevent this from happening, but in some cases 270*a1a3b679SAndreas Boehler * we can detected this and return an error instead. 271*a1a3b679SAndreas Boehler * 272*a1a3b679SAndreas Boehler * @depends testPut 273*a1a3b679SAndreas Boehler */ 274*a1a3b679SAndreas Boehler function testFinderPutSuccess() { 275*a1a3b679SAndreas Boehler 276*a1a3b679SAndreas Boehler $request = new HTTP\Request( 277*a1a3b679SAndreas Boehler 'PUT', 278*a1a3b679SAndreas Boehler '/file2', 279*a1a3b679SAndreas Boehler ['X-Expected-Entity-Length' => '5'], 280*a1a3b679SAndreas Boehler 'hello' 281*a1a3b679SAndreas Boehler ); 282*a1a3b679SAndreas Boehler $response = $this->request($request); 283*a1a3b679SAndreas Boehler 284*a1a3b679SAndreas Boehler $this->assertEquals(201, $response->getStatus()); 285*a1a3b679SAndreas Boehler 286*a1a3b679SAndreas Boehler $this->assertEquals( 287*a1a3b679SAndreas Boehler 'hello', 288*a1a3b679SAndreas Boehler $this->server->tree->getNodeForPath('file2')->get() 289*a1a3b679SAndreas Boehler ); 290*a1a3b679SAndreas Boehler 291*a1a3b679SAndreas Boehler $this->assertEquals( 292*a1a3b679SAndreas Boehler [ 293*a1a3b679SAndreas Boehler 'X-Sabre-Version' => [Version::VERSION], 294*a1a3b679SAndreas Boehler 'Content-Length' => ['0'], 295*a1a3b679SAndreas Boehler 'ETag' => ['"' . md5('hello') . '"'], 296*a1a3b679SAndreas Boehler ], 297*a1a3b679SAndreas Boehler $response->getHeaders() 298*a1a3b679SAndreas Boehler ); 299*a1a3b679SAndreas Boehler 300*a1a3b679SAndreas Boehler } 301*a1a3b679SAndreas Boehler 302*a1a3b679SAndreas Boehler /** 303*a1a3b679SAndreas Boehler * Same as the last one, but in this case we're mimicing a failed request. 304*a1a3b679SAndreas Boehler * 305*a1a3b679SAndreas Boehler * @depends testFinderPutSuccess 306*a1a3b679SAndreas Boehler */ 307*a1a3b679SAndreas Boehler function testFinderPutFail() { 308*a1a3b679SAndreas Boehler 309*a1a3b679SAndreas Boehler $request = new HTTP\Request( 310*a1a3b679SAndreas Boehler 'PUT', 311*a1a3b679SAndreas Boehler '/file2', 312*a1a3b679SAndreas Boehler ['X-Expected-Entity-Length' => '5'], 313*a1a3b679SAndreas Boehler '' 314*a1a3b679SAndreas Boehler ); 315*a1a3b679SAndreas Boehler 316*a1a3b679SAndreas Boehler $response = $this->request($request); 317*a1a3b679SAndreas Boehler 318*a1a3b679SAndreas Boehler $this->assertEquals(403, $response->getStatus()); 319*a1a3b679SAndreas Boehler 320*a1a3b679SAndreas Boehler } 321*a1a3b679SAndreas Boehler 322*a1a3b679SAndreas Boehler /** 323*a1a3b679SAndreas Boehler * Plugins can intercept PUT. We need to make sure that works. 324*a1a3b679SAndreas Boehler * 325*a1a3b679SAndreas Boehler * @depends testPut 326*a1a3b679SAndreas Boehler */ 327*a1a3b679SAndreas Boehler function testPutIntercept() { 328*a1a3b679SAndreas Boehler 329*a1a3b679SAndreas Boehler $this->server->on('beforeBind', function($uri) { 330*a1a3b679SAndreas Boehler $this->server->httpResponse->setStatus(418); 331*a1a3b679SAndreas Boehler return false; 332*a1a3b679SAndreas Boehler }); 333*a1a3b679SAndreas Boehler 334*a1a3b679SAndreas Boehler $request = new HTTP\Request('PUT', '/file2', [], 'hello'); 335*a1a3b679SAndreas Boehler $response = $this->request($request); 336*a1a3b679SAndreas Boehler 337*a1a3b679SAndreas Boehler $this->assertEquals(418, $response->getStatus(), 'Incorrect status code received. Full response body: ' .$response->getBodyAsString()); 338*a1a3b679SAndreas Boehler 339*a1a3b679SAndreas Boehler $this->assertFalse( 340*a1a3b679SAndreas Boehler $this->server->tree->nodeExists('file2') 341*a1a3b679SAndreas Boehler ); 342*a1a3b679SAndreas Boehler 343*a1a3b679SAndreas Boehler $this->assertEquals([ 344*a1a3b679SAndreas Boehler 'X-Sabre-Version' => [Version::VERSION], 345*a1a3b679SAndreas Boehler ], $response->getHeaders()); 346*a1a3b679SAndreas Boehler 347*a1a3b679SAndreas Boehler } 348*a1a3b679SAndreas Boehler 349*a1a3b679SAndreas Boehler} 350