Binary event message is used to submit form data with files upload to server. Data message format: | event | file_header | file_data | file_header | file_data | ... The 8 bytes at the beginning of each segment indicate the number of bytes remaining in the segment. event: {
(data: bytes)
| 54 | |
| 55 | |
| 56 | def deserialize_binary_event(data: bytes): |
| 57 | """ |
| 58 | Binary event message is used to submit form data with files upload to server. |
| 59 | |
| 60 | Data message format: |
| 61 | | event | file_header | file_data | file_header | file_data | ... |
| 62 | |
| 63 | The 8 bytes at the beginning of each segment indicate the number of bytes remaining in the segment. |
| 64 | |
| 65 | event: { |
| 66 | ... |
| 67 | data: { |
| 68 | input_name => input_data, |
| 69 | ... |
| 70 | } |
| 71 | } |
| 72 | |
| 73 | file_header: { |
| 74 | 'filename': file name, |
| 75 | 'size': file size, |
| 76 | 'mime_type': file type, |
| 77 | 'last_modified': last_modified timestamp, |
| 78 | 'input_name': name of input field |
| 79 | } |
| 80 | |
| 81 | file_data is the file content in bytes. |
| 82 | |
| 83 | - When a form field is not a file input, the `event['data'][input_name]` will be the value of the form field. |
| 84 | - When a form field is a single file, the `event['data'][input_name]` is None, |
| 85 | and there will only be one file_header+file_data for the field. |
| 86 | - When a form field is a multiple files, the `event['data'][input_name]` is [], |
| 87 | and there may be multiple file_header+file_data for the field. |
| 88 | |
| 89 | Example: |
| 90 | b'\x00\x00\x00\x00\x00\x00\x00E{"event":"from_submit","task_id":"main-4788341456","data":{"data":1}}\x00\x00\x00\x00\x00\x00\x00Y{"filename":"hello.txt","size":2,"mime_type":"text/plain","last_modified":1617119937.276}\x00\x00\x00\x00\x00\x00\x00\x02ss' |
| 91 | """ |
| 92 | # split data into segments |
| 93 | parts = [] |
| 94 | start_idx = 0 |
| 95 | while start_idx < len(data): |
| 96 | size = int.from_bytes(data[start_idx:start_idx + 8], "big") |
| 97 | start_idx += 8 |
| 98 | content = data[start_idx:start_idx + size] |
| 99 | parts.append(content) |
| 100 | start_idx += size |
| 101 | |
| 102 | event = json.loads(parts[0]) |
| 103 | |
| 104 | # deserialize file data |
| 105 | files = defaultdict(list) |
| 106 | for idx in range(1, len(parts), 2): |
| 107 | file_header = json.loads(parts[idx]) |
| 108 | file_header['content'] = parts[idx + 1] |
| 109 | |
| 110 | # Security fix: to avoid interpreting file name as path |
| 111 | file_header['filename'] = os.path.basename(file_header['filename']) |
| 112 | |
| 113 | input_name = file_header.pop('input_name') |
no test coverage detected
searching dependent graphs…