Skip to content
Projeler
Gruplar
Parçacıklar
Yardım
Yükleniyor...
Oturum aç / Kaydol
Gezinmeyi değiştir
D
django
Proje
Proje
Ayrıntılar
Etkinlik
Cycle Analytics
Depo (repository)
Depo (repository)
Dosyalar
Kayıtlar (commit)
Dallar (branch)
Etiketler
Katkıda bulunanlar
Grafik
Karşılaştır
Grafikler
Konular (issue)
0
Konular (issue)
0
Liste
Pano
Etiketler
Kilometre Taşları
Birleştirme (merge) Talepleri
0
Birleştirme (merge) Talepleri
0
CI / CD
CI / CD
İş akışları (pipeline)
İşler
Zamanlamalar
Grafikler
Paketler
Paketler
Wiki
Wiki
Parçacıklar
Parçacıklar
Üyeler
Üyeler
Collapse sidebar
Close sidebar
Etkinlik
Grafik
Grafikler
Yeni bir konu (issue) oluştur
İşler
Kayıtlar (commit)
Konu (issue) Panoları
Kenar çubuğunu aç
Batuhan Osman TASKAYA
django
Commits
3d2cae08
Kaydet (Commit)
3d2cae08
authored
Ock 03, 2015
tarafından
Collin Anderson
Kaydeden (comit)
Tim Graham
Ock 05, 2015
Dosyalara gözat
Seçenekler
Dosyalara Gözat
İndir
Eposta Yamaları
Sade Fark
Fixed #24072 -- Added FileResponse for streaming binary files.
üst
05f702b9
Hide whitespace changes
Inline
Side-by-side
Showing
9 changed files
with
88 additions
and
9 deletions
+88
-9
wsgi.py
django/core/handlers/wsgi.py
+2
-0
__init__.py
django/http/__init__.py
+5
-3
response.py
django/http/response.py
+19
-0
static.py
django/views/static.py
+2
-3
request-response.txt
docs/ref/request-response.txt
+18
-0
1.8.txt
docs/releases/1.8.txt
+2
-0
tests.py
tests/middleware/tests.py
+16
-2
tests.py
tests/wsgi/tests.py
+22
-0
urls.py
tests/wsgi/urls.py
+2
-1
No files found.
django/core/handlers/wsgi.py
Dosyayı görüntüle @
3d2cae08
...
@@ -197,6 +197,8 @@ class WSGIHandler(base.BaseHandler):
...
@@ -197,6 +197,8 @@ class WSGIHandler(base.BaseHandler):
for
c
in
response
.
cookies
.
values
():
for
c
in
response
.
cookies
.
values
():
response_headers
.
append
((
str
(
'Set-Cookie'
),
str
(
c
.
output
(
header
=
''
))))
response_headers
.
append
((
str
(
'Set-Cookie'
),
str
(
c
.
output
(
header
=
''
))))
start_response
(
force_str
(
status
),
response_headers
)
start_response
(
force_str
(
status
),
response_headers
)
if
getattr
(
response
,
'file_to_stream'
,
None
)
is
not
None
and
environ
.
get
(
'wsgi.file_wrapper'
):
response
=
environ
[
'wsgi.file_wrapper'
](
response
.
file_to_stream
)
return
response
return
response
...
...
django/http/__init__.py
Dosyayı görüntüle @
3d2cae08
from
django.http.cookie
import
SimpleCookie
,
parse_cookie
from
django.http.cookie
import
SimpleCookie
,
parse_cookie
from
django.http.request
import
(
HttpRequest
,
QueryDict
,
from
django.http.request
import
(
HttpRequest
,
QueryDict
,
RawPostDataException
,
UnreadablePostError
,
build_request_repr
)
RawPostDataException
,
UnreadablePostError
,
build_request_repr
)
from
django.http.response
import
(
HttpResponse
,
StreamingHttpResponse
,
from
django.http.response
import
(
HttpResponse
,
StreamingHttpResponse
,
FileResponse
,
HttpResponseRedirect
,
HttpResponsePermanentRedirect
,
HttpResponseRedirect
,
HttpResponsePermanentRedirect
,
HttpResponseNotModified
,
HttpResponseBadRequest
,
HttpResponseForbidden
,
HttpResponseNotModified
,
HttpResponseBadRequest
,
HttpResponseForbidden
,
HttpResponseNotFound
,
HttpResponseNotAllowed
,
HttpResponseGone
,
HttpResponseNotFound
,
HttpResponseNotAllowed
,
HttpResponseGone
,
HttpResponseServerError
,
Http404
,
BadHeaderError
,
JsonResponse
)
HttpResponseServerError
,
Http404
,
BadHeaderError
,
JsonResponse
,
)
from
django.http.utils
import
fix_location_header
,
conditional_content_removal
from
django.http.utils
import
fix_location_header
,
conditional_content_removal
__all__
=
[
__all__
=
[
...
@@ -16,5 +18,5 @@ __all__ = [
...
@@ -16,5 +18,5 @@ __all__ = [
'HttpResponseBadRequest'
,
'HttpResponseForbidden'
,
'HttpResponseNotFound'
,
'HttpResponseBadRequest'
,
'HttpResponseForbidden'
,
'HttpResponseNotFound'
,
'HttpResponseNotAllowed'
,
'HttpResponseGone'
,
'HttpResponseServerError'
,
'HttpResponseNotAllowed'
,
'HttpResponseGone'
,
'HttpResponseServerError'
,
'Http404'
,
'BadHeaderError'
,
'fix_location_header'
,
'JsonResponse'
,
'Http404'
,
'BadHeaderError'
,
'fix_location_header'
,
'JsonResponse'
,
'conditional_content_removal'
,
'
FileResponse'
,
'
conditional_content_removal'
,
]
]
django/http/response.py
Dosyayı görüntüle @
3d2cae08
...
@@ -417,6 +417,9 @@ class StreamingHttpResponse(HttpResponseBase):
...
@@ -417,6 +417,9 @@ class StreamingHttpResponse(HttpResponseBase):
@streaming_content.setter
@streaming_content.setter
def
streaming_content
(
self
,
value
):
def
streaming_content
(
self
,
value
):
self
.
_set_streaming_content
(
value
)
def
_set_streaming_content
(
self
,
value
):
# Ensure we can never iterate on "value" more than once.
# Ensure we can never iterate on "value" more than once.
self
.
_iterator
=
iter
(
value
)
self
.
_iterator
=
iter
(
value
)
if
hasattr
(
value
,
'close'
):
if
hasattr
(
value
,
'close'
):
...
@@ -429,6 +432,22 @@ class StreamingHttpResponse(HttpResponseBase):
...
@@ -429,6 +432,22 @@ class StreamingHttpResponse(HttpResponseBase):
return
b
''
.
join
(
self
.
streaming_content
)
return
b
''
.
join
(
self
.
streaming_content
)
class
FileResponse
(
StreamingHttpResponse
):
"""
A streaming HTTP response class optimized for files.
"""
block_size
=
4096
def
_set_streaming_content
(
self
,
value
):
if
hasattr
(
value
,
'read'
):
self
.
file_to_stream
=
value
filelike
=
value
value
=
iter
(
lambda
:
filelike
.
read
(
self
.
block_size
),
b
''
)
else
:
self
.
file_to_stream
=
None
super
(
FileResponse
,
self
)
.
_set_streaming_content
(
value
)
class
HttpResponseRedirectBase
(
HttpResponse
):
class
HttpResponseRedirectBase
(
HttpResponse
):
allowed_schemes
=
[
'http'
,
'https'
,
'ftp'
]
allowed_schemes
=
[
'http'
,
'https'
,
'ftp'
]
...
...
django/views/static.py
Dosyayı görüntüle @
3d2cae08
...
@@ -11,7 +11,7 @@ import posixpath
...
@@ -11,7 +11,7 @@ import posixpath
import
re
import
re
from
django.http
import
(
Http404
,
HttpResponse
,
HttpResponseRedirect
,
from
django.http
import
(
Http404
,
HttpResponse
,
HttpResponseRedirect
,
HttpResponseNotModified
,
StreamingHttp
Response
)
HttpResponseNotModified
,
File
Response
)
from
django.template
import
loader
,
Template
,
Context
,
TemplateDoesNotExist
from
django.template
import
loader
,
Template
,
Context
,
TemplateDoesNotExist
from
django.utils.http
import
http_date
,
parse_http_date
from
django.utils.http
import
http_date
,
parse_http_date
from
django.utils.six.moves.urllib.parse
import
unquote
from
django.utils.six.moves.urllib.parse
import
unquote
...
@@ -63,8 +63,7 @@ def serve(request, path, document_root=None, show_indexes=False):
...
@@ -63,8 +63,7 @@ def serve(request, path, document_root=None, show_indexes=False):
return
HttpResponseNotModified
()
return
HttpResponseNotModified
()
content_type
,
encoding
=
mimetypes
.
guess_type
(
fullpath
)
content_type
,
encoding
=
mimetypes
.
guess_type
(
fullpath
)
content_type
=
content_type
or
'application/octet-stream'
content_type
=
content_type
or
'application/octet-stream'
response
=
StreamingHttpResponse
(
open
(
fullpath
,
'rb'
),
response
=
FileResponse
(
open
(
fullpath
,
'rb'
),
content_type
=
content_type
)
content_type
=
content_type
)
response
[
"Last-Modified"
]
=
http_date
(
statobj
.
st_mtime
)
response
[
"Last-Modified"
]
=
http_date
(
statobj
.
st_mtime
)
if
stat
.
S_ISREG
(
statobj
.
st_mode
):
if
stat
.
S_ISREG
(
statobj
.
st_mode
):
response
[
"Content-Length"
]
=
statobj
.
st_size
response
[
"Content-Length"
]
=
statobj
.
st_size
...
...
docs/ref/request-response.txt
Dosyayı görüntüle @
3d2cae08
...
@@ -998,3 +998,21 @@ Attributes
...
@@ -998,3 +998,21 @@ Attributes
.. attribute:: StreamingHttpResponse.streaming
.. attribute:: StreamingHttpResponse.streaming
This is always ``True``.
This is always ``True``.
FileResponse objects
====================
.. versionadded:: 1.8
.. class:: FileResponse
:class:`FileResponse` is a subclass of :class:`StreamingHttpResponse` optimized
for binary files. It uses `wsgi.file_wrapper`_ if provided by the wsgi server,
otherwise it streams the file out in small chunks.
.. _wsgi.file_wrapper: https://www.python.org/dev/peps/pep-3333/#optional-platform-specific-file-handling
``FileResponse`` expects a file open in binary mode like so::
>>> from django.http import FileResponse
>>> response = FileResponse(open('myfile.png', 'rb'))
docs/releases/1.8.txt
Dosyayı görüntüle @
3d2cae08
...
@@ -559,6 +559,8 @@ Requests and Responses
...
@@ -559,6 +559,8 @@ Requests and Responses
<django.http.HttpResponse.setdefault>` method allows setting a header unless
<django.http.HttpResponse.setdefault>` method allows setting a header unless
it has already been set.
it has already been set.
* You can use the new :class:`~django.http.FileResponse` to stream files.
* The :func:`~django.views.decorators.http.condition` decorator for
* The :func:`~django.views.decorators.http.condition` decorator for
conditional view processing now supports the ``If-unmodified-since`` header.
conditional view processing now supports the ``If-unmodified-since`` header.
...
...
tests/middleware/tests.py
Dosyayı görüntüle @
3d2cae08
...
@@ -10,8 +10,8 @@ from unittest import skipIf
...
@@ -10,8 +10,8 @@ from unittest import skipIf
from
django.conf
import
settings
from
django.conf
import
settings
from
django.core
import
mail
from
django.core
import
mail
from
django.http
import
(
from
django.http
import
(
HttpRequest
,
HttpResponse
,
StreamingHttpResponse
,
HttpResponsePermanentRedirect
,
HttpRequest
,
HttpResponse
,
StreamingHttpResponse
,
FileResponse
,
HttpResponseRedirect
,
HttpResponseRedirect
,
HttpResponsePermanentRedirect
,
)
)
from
django.middleware.clickjacking
import
XFrameOptionsMiddleware
from
django.middleware.clickjacking
import
XFrameOptionsMiddleware
from
django.middleware.common
import
CommonMiddleware
,
BrokenLinkEmailsMiddleware
from
django.middleware.common
import
CommonMiddleware
,
BrokenLinkEmailsMiddleware
...
@@ -624,6 +624,20 @@ class GZipMiddlewareTest(TestCase):
...
@@ -624,6 +624,20 @@ class GZipMiddlewareTest(TestCase):
self
.
assertEqual
(
r
.
get
(
'Content-Encoding'
),
'gzip'
)
self
.
assertEqual
(
r
.
get
(
'Content-Encoding'
),
'gzip'
)
self
.
assertFalse
(
r
.
has_header
(
'Content-Length'
))
self
.
assertFalse
(
r
.
has_header
(
'Content-Length'
))
def
test_compress_file_response
(
self
):
"""
Tests that compression is performed on FileResponse.
"""
open_file
=
lambda
:
open
(
__file__
,
'rb'
)
with
open_file
()
as
file1
:
file_resp
=
FileResponse
(
file1
)
file_resp
[
'Content-Type'
]
=
'text/html; charset=UTF-8'
r
=
GZipMiddleware
()
.
process_response
(
self
.
req
,
file_resp
)
with
open_file
()
as
file2
:
self
.
assertEqual
(
self
.
decompress
(
b
''
.
join
(
r
)),
file2
.
read
())
self
.
assertEqual
(
r
.
get
(
'Content-Encoding'
),
'gzip'
)
self
.
assertIsNot
(
r
.
file_to_stream
,
file1
)
def
test_compress_non_200_response
(
self
):
def
test_compress_non_200_response
(
self
):
"""
"""
Tests that compression is performed on responses with a status other than 200.
Tests that compression is performed on responses with a status other than 200.
...
...
tests/wsgi/tests.py
Dosyayı görüntüle @
3d2cae08
...
@@ -51,6 +51,28 @@ class WSGITest(TestCase):
...
@@ -51,6 +51,28 @@ class WSGITest(TestCase):
bytes
(
response
),
bytes
(
response
),
b
"Content-Type: text/html; charset=utf-8
\r\n\r\n
Hello World!"
)
b
"Content-Type: text/html; charset=utf-8
\r\n\r\n
Hello World!"
)
def
test_file_wrapper
(
self
):
"""
Verify that FileResponse uses wsgi.file_wrapper.
"""
class
FileWrapper
(
object
):
def
__init__
(
self
,
filelike
,
blksize
=
8192
):
filelike
.
close
()
application
=
get_wsgi_application
()
environ
=
RequestFactory
()
.
_base_environ
(
PATH_INFO
=
'/file/'
,
REQUEST_METHOD
=
'GET'
,
**
{
'wsgi.file_wrapper'
:
FileWrapper
}
)
response_data
=
{}
def
start_response
(
status
,
headers
):
response_data
[
'status'
]
=
status
response_data
[
'headers'
]
=
headers
response
=
application
(
environ
,
start_response
)
self
.
assertEqual
(
response_data
[
'status'
],
'200 OK'
)
self
.
assertIsInstance
(
response
,
FileWrapper
)
class
GetInternalWSGIApplicationTest
(
unittest
.
TestCase
):
class
GetInternalWSGIApplicationTest
(
unittest
.
TestCase
):
@override_settings
(
WSGI_APPLICATION
=
"wsgi.wsgi.application"
)
@override_settings
(
WSGI_APPLICATION
=
"wsgi.wsgi.application"
)
...
...
tests/wsgi/urls.py
Dosyayı görüntüle @
3d2cae08
from
django.conf.urls
import
url
from
django.conf.urls
import
url
from
django.http
import
HttpResponse
from
django.http
import
HttpResponse
,
FileResponse
def
helloworld
(
request
):
def
helloworld
(
request
):
...
@@ -7,4 +7,5 @@ def helloworld(request):
...
@@ -7,4 +7,5 @@ def helloworld(request):
urlpatterns
=
[
urlpatterns
=
[
url
(
"^$"
,
helloworld
),
url
(
"^$"
,
helloworld
),
url
(
r'^file/$'
,
lambda
x
:
FileResponse
(
open
(
__file__
,
'rb'
))),
]
]
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment