Issue 2551068
Created on 2019-10-28 00:29 by rouilj, last changed 2024-12-08 22:46 by rouilj.
Messages | |||
---|---|---|---|
msg6780 | Author: [hidden] (rouilj) | Date: 2019-10-28 00:29 | |
From msg6749: ==== ... I wonder if we should provide a way via the rest interface to download just the content data in raw form. I think the right way to do this is to make the request to demo/data/file/11/content but set the header: Accept: image/vnd.microsoft.icon If the content type matches the file type, respond with a binary data stream with appropriate Content-Type (either the same as the Accept type or application/octet-stream) and Content-Length. If it doesn't match we return 406 - not acceptable. === If we do not set an acept header, or set accept to application/json or application/xml (if enabled) we get back the standard data wrapped output like (json format): { "data": { "id": "1", "type": "file", "link": "https://.../demo/rest/data/file/1", "attributes": { "content": { "link": "https://.../demo/file1/" }, "name": "android-chrome-192x192.png", }, "type": "image/png" }, "@etag": "\"94c0e14629da6944d9ab2a83546d0737\"" } } Details and discussion are on: issue2551067 specifically at msg6749 |
|||
msg7823 | Author: [hidden] (rouilj) | Date: 2023-08-02 21:59 | |
Also see issue 2551289 for changes to handling Accept headers that are not json or xml. This should allow downloading the binary_content in raw format without encoding. |
|||
msg8212 | Author: [hidden] (rouilj) | Date: 2024-12-08 07:18 | |
A new method determine_output_format(self, uri) was added in issue 2551289 to refactor the dispatch method. One thought could be to modify determine_output_format() to check for a trailing 'binary_content' element in the path. For example: curl -X GET -u admin -H "Accept: image/png" -H "X-Requested-With: rest" \ https://example.com/tracker/rest/data/file/54/binary_content results in: self.client.request.path '/tracker/rest/data/file/54/binary_content' Parsing the path and splitting the designator allows getting the mime type of the file via self.client.db.file.get('54', 'type') -> 'image/png' This can be compared to the Accept header in the `for part in accept_header:` loop by adding: if part[0] == file_type: accept_type = file_type this should result in a call to get_attribute(self, class_name, item_id, attr_name, input) which returns the binary data in a dict. Which then calls format_dispatch_output(). Then changing format_dispatch_output(self, accept_mime_type, output, pretty_print) to add the right content type header and return the output['data']['data'] element if the accept_mime_type is defined. (Note: accept_mime_type should never be undefined/None with the change to fix issue 2551289.) Also in the debugger using open('file', 'wb').write(output['data']['data'] wrote my test png file just fine. Just need to make sure I can write raw binary data to the http socket. |
|||
msg8213 | Author: [hidden] (rouilj) | Date: 2024-12-08 07:27 | |
For msg type, I need to handle the case where type is empty. Seems that msg doesn't always set that type. I assume text/plain (or text/x-rst or text/markdown) would be suitable depending on what the frontend support for markup. Maybe support a mime type of text/* in Accept?? For text output, that seems reasonable while binary formats should not allow a wildcard subtype. |
|||
msg8214 | Author: [hidden] (rouilj) | Date: 2024-12-08 07:36 | |
Other tricks: So this is an easy way of determining if my db class is a Fileclass. (Pdb) from roundup.hyperdb import FileClass (Pdb) isinstance( self.db.msg, FileClass) True (Pdb) isinstance( self.db.status, FileClass) False (Pdb) isinstance( self.db.file, FileClass) True I think this works regardless of the back end as: (Pdb) p self.db.msg.__class__ <class 'roundup.backends.back_sqlite.FileClass'> could work using string comparison of the right type (ugh). This should work if I need to access the data by parsing the path/designator. self.db.getclass('msg').get("2", "binary_content") but I think just passing it through dispatch will do the trick. |
|||
msg8216 | Author: [hidden] (rouilj) | Date: 2024-12-08 16:06 | |
Handle application/octet-stream as a universal download mime type. However without the 'X-Content-Type-Options: nosniff' security header, an html file with application/octet-stream could be parsed by the browser and displayed/executed as html. So set the X-Content-Type-Options header when using this codepath. client.py sets this header when the SendFile exception is raised for the same reason. |
|||
msg8217 | Author: [hidden] (rouilj) | Date: 2024-12-08 21:54 | |
The existing example in rest.txt shows the content property using the html interface. "content": { "link": "https://.../demo/msg11/" }, I think this is ok since we are using the binary_content property for retrieval. Also text/* is supported for file/msg without a mime type. I'm not sure if there are security implications for this. Could somebody craft a binary file and set it without a mime type and do something strange? We set header to block browser sniffing, so I think it's ok. |
|||
msg8218 | Author: [hidden] (rouilj) | Date: 2024-12-08 22:46 | |
Committed first attempt in changeset: 8180:d02ce1d14acd. CI passed. Closing. |
History | |||
---|---|---|---|
Date | User | Action | Args |
2024-12-08 22:46:16 | rouilj | set | status: open -> fixed resolution: fixed messages: + msg8218 |
2024-12-08 21:55:00 | rouilj | set | status: new -> open messages: + msg8217 |
2024-12-08 16:06:09 | rouilj | set | messages: + msg8216 |
2024-12-08 07:36:43 | rouilj | set | messages: + msg8214 |
2024-12-08 07:27:23 | rouilj | set | assignee: rouilj messages: + msg8213 |
2024-12-08 07:18:00 | rouilj | set | messages: + msg8212 |
2023-08-02 21:59:48 | rouilj | set | messages: + msg7823 |
2019-10-28 15:16:20 | schlatterbeck | set | nosy: + schlatterbeck |
2019-10-28 00:29:03 | rouilj | create |