Subversion Repositories php-qbpwcf

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
3 liveuser 1
<?php
2
 
3
/*
4
 * This file is part of the Symfony package.
5
 *
6
 * (c) Fabien Potencier <fabien@symfony.com>
7
 *
8
 * For the full copyright and license information, please view the LICENSE
9
 * file that was distributed with this source code.
10
 */
11
 
12
namespace Symfony\Component\HttpFoundation\Tests;
13
 
14
use Symfony\Component\HttpFoundation\BinaryFileResponse;
15
use Symfony\Component\HttpFoundation\Request;
16
use Symfony\Component\HttpFoundation\ResponseHeaderBag;
17
use Symfony\Component\HttpFoundation\Tests\File\FakeFile;
18
 
19
class BinaryFileResponseTest extends ResponseTestCase
20
{
21
    public function testConstruction()
22
    {
23
        $file = __DIR__.'/../README.md';
24
        $response = new BinaryFileResponse($file, 404, array('X-Header' => 'Foo'), true, null, true, true);
25
        $this->assertEquals(404, $response->getStatusCode());
26
        $this->assertEquals('Foo', $response->headers->get('X-Header'));
27
        $this->assertTrue($response->headers->has('ETag'));
28
        $this->assertTrue($response->headers->has('Last-Modified'));
29
        $this->assertFalse($response->headers->has('Content-Disposition'));
30
 
31
        $response = BinaryFileResponse::create($file, 404, array(), true, ResponseHeaderBag::DISPOSITION_INLINE);
32
        $this->assertEquals(404, $response->getStatusCode());
33
        $this->assertFalse($response->headers->has('ETag'));
34
        $this->assertEquals('inline; filename="README.md"', $response->headers->get('Content-Disposition'));
35
    }
36
 
37
    public function testConstructWithNonAsciiFilename()
38
    {
39
        touch(sys_get_temp_dir().'/fööö.html');
40
 
41
        $response = new BinaryFileResponse(sys_get_temp_dir().'/fööö.html', 200, array(), true, 'attachment');
42
 
43
        @unlink(sys_get_temp_dir().'/fööö.html');
44
 
45
        $this->assertSame('fööö.html', $response->getFile()->getFilename());
46
    }
47
 
48
    /**
49
     * @expectedException \LogicException
50
     */
51
    public function testSetContent()
52
    {
53
        $response = new BinaryFileResponse(__FILE__);
54
        $response->setContent('foo');
55
    }
56
 
57
    public function testGetContent()
58
    {
59
        $response = new BinaryFileResponse(__FILE__);
60
        $this->assertFalse($response->getContent());
61
    }
62
 
63
    public function testSetContentDispositionGeneratesSafeFallbackFilename()
64
    {
65
        $response = new BinaryFileResponse(__FILE__);
66
        $response->setContentDisposition(ResponseHeaderBag::DISPOSITION_ATTACHMENT, 'föö.html');
67
 
68
        $this->assertSame('attachment; filename="f__.html"; filename*=utf-8\'\'f%C3%B6%C3%B6.html', $response->headers->get('Content-Disposition'));
69
    }
70
 
71
    /**
72
     * @dataProvider provideRanges
73
     */
74
    public function testRequests($requestRange, $offset, $length, $responseRange)
75
    {
76
        $response = BinaryFileResponse::create(__DIR__.'/File/Fixtures/test.gif', 200, array('Content-Type' => 'application/octet-stream'))->setAutoEtag();
77
 
78
        // do a request to get the ETag
79
        $request = Request::create('/');
80
        $response->prepare($request);
81
        $etag = $response->headers->get('ETag');
82
 
83
        // prepare a request for a range of the testing file
84
        $request = Request::create('/');
85
        $request->headers->set('If-Range', $etag);
86
        $request->headers->set('Range', $requestRange);
87
 
88
        $file = fopen(__DIR__.'/File/Fixtures/test.gif', 'r');
89
        fseek($file, $offset);
90
        $data = fread($file, $length);
91
        fclose($file);
92
 
93
        $this->expectOutputString($data);
94
        $response = clone $response;
95
        $response->prepare($request);
96
        $response->sendContent();
97
 
98
        $this->assertEquals(206, $response->getStatusCode());
99
        $this->assertEquals($responseRange, $response->headers->get('Content-Range'));
100
    }
101
 
102
    /**
103
     * @dataProvider provideRanges
104
     */
105
    public function testRequestsWithoutEtag($requestRange, $offset, $length, $responseRange)
106
    {
107
        $response = BinaryFileResponse::create(__DIR__.'/File/Fixtures/test.gif', 200, array('Content-Type' => 'application/octet-stream'));
108
 
109
        // do a request to get the LastModified
110
        $request = Request::create('/');
111
        $response->prepare($request);
112
        $lastModified = $response->headers->get('Last-Modified');
113
 
114
        // prepare a request for a range of the testing file
115
        $request = Request::create('/');
116
        $request->headers->set('If-Range', $lastModified);
117
        $request->headers->set('Range', $requestRange);
118
 
119
        $file = fopen(__DIR__.'/File/Fixtures/test.gif', 'r');
120
        fseek($file, $offset);
121
        $data = fread($file, $length);
122
        fclose($file);
123
 
124
        $this->expectOutputString($data);
125
        $response = clone $response;
126
        $response->prepare($request);
127
        $response->sendContent();
128
 
129
        $this->assertEquals(206, $response->getStatusCode());
130
        $this->assertEquals($responseRange, $response->headers->get('Content-Range'));
131
    }
132
 
133
    public function provideRanges()
134
    {
135
        return array(
136
            array('bytes=1-4', 1, 4, 'bytes 1-4/35'),
137
            array('bytes=-5', 30, 5, 'bytes 30-34/35'),
138
            array('bytes=30-', 30, 5, 'bytes 30-34/35'),
139
            array('bytes=30-30', 30, 1, 'bytes 30-30/35'),
140
            array('bytes=30-34', 30, 5, 'bytes 30-34/35'),
141
        );
142
    }
143
 
144
    public function testRangeRequestsWithoutLastModifiedDate()
145
    {
146
        // prevent auto last modified
147
        $response = BinaryFileResponse::create(__DIR__.'/File/Fixtures/test.gif', 200, array('Content-Type' => 'application/octet-stream'), true, null, false, false);
148
 
149
        // prepare a request for a range of the testing file
150
        $request = Request::create('/');
151
        $request->headers->set('If-Range', date('D, d M Y H:i:s').' GMT');
152
        $request->headers->set('Range', 'bytes=1-4');
153
 
154
        $this->expectOutputString(file_get_contents(__DIR__.'/File/Fixtures/test.gif'));
155
        $response = clone $response;
156
        $response->prepare($request);
157
        $response->sendContent();
158
 
159
        $this->assertEquals(200, $response->getStatusCode());
160
        $this->assertNull($response->headers->get('Content-Range'));
161
    }
162
 
163
    /**
164
     * @dataProvider provideFullFileRanges
165
     */
166
    public function testFullFileRequests($requestRange)
167
    {
168
        $response = BinaryFileResponse::create(__DIR__.'/File/Fixtures/test.gif', 200, array('Content-Type' => 'application/octet-stream'))->setAutoEtag();
169
 
170
        // prepare a request for a range of the testing file
171
        $request = Request::create('/');
172
        $request->headers->set('Range', $requestRange);
173
 
174
        $file = fopen(__DIR__.'/File/Fixtures/test.gif', 'r');
175
        $data = fread($file, 35);
176
        fclose($file);
177
 
178
        $this->expectOutputString($data);
179
        $response = clone $response;
180
        $response->prepare($request);
181
        $response->sendContent();
182
 
183
        $this->assertEquals(200, $response->getStatusCode());
184
    }
185
 
186
    public function provideFullFileRanges()
187
    {
188
        return array(
189
            array('bytes=0-'),
190
            array('bytes=0-34'),
191
            array('bytes=-35'),
192
            // Syntactical invalid range-request should also return the full resource
193
            array('bytes=20-10'),
194
            array('bytes=50-40'),
195
        );
196
    }
197
 
198
    /**
199
     * @dataProvider provideInvalidRanges
200
     */
201
    public function testInvalidRequests($requestRange)
202
    {
203
        $response = BinaryFileResponse::create(__DIR__.'/File/Fixtures/test.gif', 200, array('Content-Type' => 'application/octet-stream'))->setAutoEtag();
204
 
205
        // prepare a request for a range of the testing file
206
        $request = Request::create('/');
207
        $request->headers->set('Range', $requestRange);
208
 
209
        $response = clone $response;
210
        $response->prepare($request);
211
        $response->sendContent();
212
 
213
        $this->assertEquals(416, $response->getStatusCode());
214
        $this->assertEquals('bytes */35', $response->headers->get('Content-Range'));
215
    }
216
 
217
    public function provideInvalidRanges()
218
    {
219
        return array(
220
            array('bytes=-40'),
221
            array('bytes=30-40'),
222
        );
223
    }
224
 
225
    /**
226
     * @dataProvider provideXSendfileFiles
227
     */
228
    public function testXSendfile($file)
229
    {
230
        $request = Request::create('/');
231
        $request->headers->set('X-Sendfile-Type', 'X-Sendfile');
232
 
233
        BinaryFileResponse::trustXSendfileTypeHeader();
234
        $response = BinaryFileResponse::create($file, 200, array('Content-Type' => 'application/octet-stream'));
235
        $response->prepare($request);
236
 
237
        $this->expectOutputString('');
238
        $response->sendContent();
239
 
240
        $this->assertContains('README.md', $response->headers->get('X-Sendfile'));
241
    }
242
 
243
    public function provideXSendfileFiles()
244
    {
245
        return array(
246
            array(__DIR__.'/../README.md'),
247
            array('file://'.__DIR__.'/../README.md'),
248
        );
249
    }
250
 
251
    /**
252
     * @dataProvider getSampleXAccelMappings
253
     */
254
    public function testXAccelMapping($realpath, $mapping, $virtual)
255
    {
256
        $request = Request::create('/');
257
        $request->headers->set('X-Sendfile-Type', 'X-Accel-Redirect');
258
        $request->headers->set('X-Accel-Mapping', $mapping);
259
 
260
        $file = new FakeFile($realpath, __DIR__.'/File/Fixtures/test');
261
 
262
        BinaryFileResponse::trustXSendfileTypeHeader();
263
        $response = new BinaryFileResponse($file, 200, array('Content-Type' => 'application/octet-stream'));
264
        $reflection = new \ReflectionObject($response);
265
        $property = $reflection->getProperty('file');
266
        $property->setAccessible(true);
267
        $property->setValue($response, $file);
268
 
269
        $response->prepare($request);
270
        $this->assertEquals($virtual, $response->headers->get('X-Accel-Redirect'));
271
    }
272
 
273
    public function testDeleteFileAfterSend()
274
    {
275
        $request = Request::create('/');
276
 
277
        $path = __DIR__.'/File/Fixtures/to_delete';
278
        touch($path);
279
        $realPath = realpath($path);
280
        $this->assertFileExists($realPath);
281
 
282
        $response = new BinaryFileResponse($realPath, 200, array('Content-Type' => 'application/octet-stream'));
283
        $response->deleteFileAfterSend(true);
284
 
285
        $response->prepare($request);
286
        $response->sendContent();
287
 
288
        $this->assertFileNotExists($path);
289
    }
290
 
291
    public function testAcceptRangeOnUnsafeMethods()
292
    {
293
        $request = Request::create('/', 'POST');
294
        $response = BinaryFileResponse::create(__DIR__.'/File/Fixtures/test.gif', 200, array('Content-Type' => 'application/octet-stream'));
295
        $response->prepare($request);
296
 
297
        $this->assertEquals('none', $response->headers->get('Accept-Ranges'));
298
    }
299
 
300
    public function testAcceptRangeNotOverriden()
301
    {
302
        $request = Request::create('/', 'POST');
303
        $response = BinaryFileResponse::create(__DIR__.'/File/Fixtures/test.gif', 200, array('Content-Type' => 'application/octet-stream'));
304
        $response->headers->set('Accept-Ranges', 'foo');
305
        $response->prepare($request);
306
 
307
        $this->assertEquals('foo', $response->headers->get('Accept-Ranges'));
308
    }
309
 
310
    public function getSampleXAccelMappings()
311
    {
312
        return array(
313
            array('/var/www/var/www/files/foo.txt', '/var/www/=/files/', '/files/var/www/files/foo.txt'),
314
            array('/home/foo/bar.txt', '/var/www/=/files/,/home/foo/=/baz/', '/baz/bar.txt'),
315
        );
316
    }
317
 
318
    protected function provideResponse()
319
    {
320
        return new BinaryFileResponse(__DIR__.'/../README.md', 200, array('Content-Type' => 'application/octet-stream'));
321
    }
322
 
323
    public static function tearDownAfterClass()
324
    {
325
        $path = __DIR__.'/../Fixtures/to_delete';
326
        if (file_exists($path)) {
327
            @unlink($path);
328
        }
329
    }
330
}