Skip to content

Commit

Permalink
Merge pull request #140 from algoo/fix/139_set_content_length_and_las…
Browse files Browse the repository at this point in the history
…t_modified_headers_in_HapicFile

set content_length and last modified headers using hapicFile for pyramid
  • Loading branch information
buxx authored Mar 22, 2019
2 parents db2e394 + ada8338 commit c60ac86
Show file tree
Hide file tree
Showing 4 changed files with 63 additions and 1 deletion.
5 changes: 5 additions & 0 deletions hapic/data.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
# -*- coding: utf-8 -*-
import typing
import urllib.parse
from datetime import datetime


class HapicData(object):
Expand All @@ -20,13 +21,17 @@ def __init__(
file_object: typing.Any = None,
mimetype: typing.Any = None,
filename: str = None,
content_length: int = None,
last_modified: datetime = None,
as_attachment: bool = False,
):
self.file_path = file_path
self.file_object = file_object
self.filename = filename
self.mimetype = mimetype
self.as_attachment = as_attachment
self.content_length = content_length
self.last_modified = last_modified

def get_content_disposition_header_value(self) -> str:
disposition = "inline"
Expand Down
5 changes: 5 additions & 0 deletions hapic/ext/pyramid/context.py
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,11 @@ def get_file_response(self, file_response: HapicFile, http_code: int):
response.content_type = file_response.mimetype
response.app_iter = FileIter(file_response.file_object)

if file_response.content_length:
response.content_length = file_response.content_length
if file_response.last_modified:
response.last_modified = file_response.last_modified

response.status_code = http_code
response.content_disposition = (
file_response.get_content_disposition_header_value()
Expand Down
7 changes: 7 additions & 0 deletions hapic/processor/main.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import abc
import os
import typing
from datetime import datetime

from apispec import BasePlugin
from multidict.__init__ import MultiDict
Expand Down Expand Up @@ -213,6 +214,12 @@ def _get_ouput_file_validation_error_message(
error_message = "File path is not correct, file do not exist"
elif data.file_object and not data.mimetype:
error_message = "File object should have explicit mimetype"
elif data.content_length and not isinstance(data.content_length, int):
error_message = "Content length should be integer"
elif data.content_length and data.content_length < 0:
error_message = "Content length should positive or null integer"
elif data.last_modified and not isinstance(data.last_modified, datetime):
error_message = "Last-modified value should be datetime type"
return error_message

# NOTE BS 2018-12-20: the decorators order is not semantically right,
Expand Down
47 changes: 46 additions & 1 deletion tests/unit/test_processor.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
# -*- coding: utf-8 -*-
from datetime import datetime
from io import BytesIO
import os

Expand Down Expand Up @@ -26,7 +27,7 @@ def test_unit_file_output_processor_ok__process_success_filepath(self):
data = processor.dump_output_file(tested_data)
assert data == tested_data

def test_unit_file_output_processor_ok__process_success_fileobject(self):
def test_unit_file_output_processor_ok__process_success_fileobject_as_stream(self):
processor = MarshmallowProcessor()
file = BytesIO()
image = Image.new("RGBA", size=(1000, 1000), color=(0, 0, 0))
Expand All @@ -37,6 +38,50 @@ def test_unit_file_output_processor_ok__process_success_fileobject(self):
data = processor.dump_output_file(tested_data)
assert data == tested_data

def test_unit_file_output_processor_ok__process_success_fileobject_as_sized_file(self):
processor = MarshmallowProcessor()
file = BytesIO()
image = Image.new("RGBA", size=(1000, 1000), color=(0, 0, 0))
image.save(file, "png")
file.name = "test_image.png"
file.seek(0)
tested_data = HapicFile(file_object=file, mimetype="image/png", content_length=file.getbuffer().nbytes, last_modified=datetime.utcnow())
data = processor.dump_output_file(tested_data)
assert data == tested_data

def test_unit_file_output_processor__err__bad_last_modified_type(self):
processor = MarshmallowProcessor()
file = BytesIO()
image = Image.new("RGBA", size=(1000, 1000), color=(0, 0, 0))
image.save(file, "png")
file.name = "test_image.png"
file.seek(0)
tested_data = HapicFile(file_object=file, mimetype="image/png", last_modified='uncorrect_type')
with pytest.raises(ValidationException):
data = processor.dump_output_file(tested_data)

def test_unit_file_output_processor__err__bad_content_length_type(self):
processor = MarshmallowProcessor()
file = BytesIO()
image = Image.new("RGBA", size=(1000, 1000), color=(0, 0, 0))
image.save(file, "png")
file.name = "test_image.png"
file.seek(0)
tested_data = HapicFile(file_object=file, mimetype="image/png", content_length='uncorrect_type')
with pytest.raises(ValidationException):
data = processor.dump_output_file(tested_data)

def test_unit_file_output_processor__err__negative_content_length(self):
processor = MarshmallowProcessor()
file = BytesIO()
image = Image.new("RGBA", size=(1000, 1000), color=(0, 0, 0))
image.save(file, "png")
file.name = "test_image.png"
file.seek(0)
tested_data = HapicFile(file_object=file, mimetype="image/png", content_length=-1)
with pytest.raises(ValidationException):
data = processor.dump_output_file(tested_data)

def test_unit_file_output_processor_err__wrong_type(self):
processor = MarshmallowProcessor()
file = BytesIO()
Expand Down

0 comments on commit c60ac86

Please sign in to comment.