Skip to content

Commit 634a646

Browse files
committed
fix #684: pin.get_pin_values() not work for put_file_upload()
1 parent f0ddc7c commit 634a646

File tree

3 files changed

+40
-31
lines changed

3 files changed

+40
-31
lines changed

pywebio/platform/utils.py

+8-8
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ def is_same_site(origin, host):
5555

5656
def deserialize_binary_event(data: bytes):
5757
"""
58-
Binary event message is used to submit data with files upload to server.
58+
Binary event message is used to submit form data with files upload to server.
5959
6060
Data message format:
6161
| event | file_header | file_data | file_header | file_data | ...
@@ -82,9 +82,9 @@ def deserialize_binary_event(data: bytes):
8282
8383
- When a form field is not a file input, the `event['data'][input_name]` will be the value of the form field.
8484
- 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 at most.
85+
and there will only be one file_header+file_data for the field.
8686
- When a form field is a multiple files, the `event['data'][input_name]` is [],
87-
and there may be multiple file_header+file_data.
87+
and there may be multiple file_header+file_data for the field.
8888
8989
Example:
9090
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'
@@ -104,14 +104,14 @@ def deserialize_binary_event(data: bytes):
104104
# deserialize file data
105105
files = defaultdict(list)
106106
for idx in range(1, len(parts), 2):
107-
f = json.loads(parts[idx])
108-
f['content'] = parts[idx + 1]
107+
file_header = json.loads(parts[idx])
108+
file_header['content'] = parts[idx + 1]
109109

110110
# Security fix: to avoid interpreting file name as path
111-
f['filename'] = os.path.basename(f['filename'])
111+
file_header['filename'] = os.path.basename(file_header['filename'])
112112

113-
input_name = f.pop('input_name')
114-
files[input_name].append(f)
113+
input_name = file_header.pop('input_name')
114+
files[input_name].append(file_header)
115115

116116
# fill file data to event
117117
for input_name in list(event['data'].keys()):

webiojs/src/handlers/input.ts

+1-3
Original file line numberDiff line numberDiff line change
@@ -258,9 +258,7 @@ class FormController {
258258
input_data[name] = value;
259259
if (that.spec.inputs[idx].type == 'file') {
260260
input_data[name] = value.multiple ? [] : null;
261-
value.files.forEach((file: File) => {
262-
files.push(serialize_file(file, name))
263-
});
261+
files.push(...value.files.map((file: File) => serialize_file(file, name)));
264262
}
265263
}
266264
let msg = {

webiojs/src/handlers/pin.ts

+31-20
Original file line numberDiff line numberDiff line change
@@ -23,18 +23,24 @@ export class PinHandler implements CommandHandler {
2323
task_id: msg.task_id,
2424
data: values
2525
};
26-
this.submit(send_msg, IsFileInput(msg.spec.name));
26+
this.submit(
27+
send_msg,
28+
msg.spec.names.filter(IsFileInput)
29+
);
2730
} else if (msg.command === 'pin_update') {
2831
PinUpdate(msg.spec.name, msg.spec.attributes);
2932
} else if (msg.command === 'pin_wait') {
3033
let p = WaitChange(msg.spec.names, msg.spec.timeout);
3134
Promise.resolve(p).then((change_info: (null | { name: string, value: any })) => {
3235
// change_info: null or {'name': name, 'value': value}
33-
let send_msg = {event: "js_yield", task_id: msg.task_id, data: change_info}
34-
this.submit(send_msg, IsFileInput(change_info.name));
36+
let send_msg = {event: "js_yield", task_id: msg.task_id, data: change_info};
37+
this.submit(
38+
send_msg,
39+
(change_info && IsFileInput(change_info.name)) ? ['value'] : []
40+
);
3541
}).catch((error) => {
3642
console.error('error in `pin_wait`: %s', error);
37-
this.submit({event: "js_yield", task_id: msg.task_id, data: null});
43+
this.submit({event: "js_yield", task_id: msg.task_id, data: null}, []);
3844
});
3945
} else if (msg.command === 'pin_onchange') {
4046
let onchange = (val: any) => {
@@ -43,43 +49,48 @@ export class PinHandler implements CommandHandler {
4349
task_id: msg.spec.callback_id,
4450
data: {value: val}
4551
}
46-
this.submit(send_msg, IsFileInput(msg.spec.name));
52+
this.submit(
53+
send_msg,
54+
IsFileInput(msg.spec.name)? ['value'] : []
55+
);
4756
}
4857
PinChangeCallback(msg.spec.name, msg.spec.callback_id ? onchange : null, msg.spec.clear);
4958
}
5059
}
5160

5261
/*
53-
* Send pin value to server.
54-
* `msg.data` may be null, or {value: any, ...}
55-
* `msg.data.value` stores the value of the pin.
56-
* when submit files, `msg.data.value` is {multiple: bool, files: File[] }
62+
* Send pin values to server.
63+
* `msg.data`: {input_name: input_value, ...} or null
64+
* for file input, the `input_value` is in {multiple: bool, files: File[] }
5765
* */
58-
submit(msg: ClientEvent, is_file: boolean = false) {
59-
if (is_file && msg.data !== null) {
60-
// msg.data.value: {multiple: bool, files: File[]}
61-
let {multiple, files} = msg.data.value;
62-
msg.data.value = multiple ? [] : null; // replace file value with initial value
66+
submit(msg: ClientEvent, file_input_names: string[]) {
67+
// See: deserialize_binary_event() in pywebio/platform/utils.py
68+
let file_blobs:Blob[] = [];
69+
for (let name of file_input_names) {
70+
if (msg.data && msg.data[name]) {
71+
// {multiple: bool, files: File[]}
72+
let {multiple, files} = msg.data[name];
73+
msg.data[name] = multiple ? [] : null; // replace file value with initial value
74+
file_blobs.push(...files.map((file: File) => serialize_file(file, name)));
75+
}
76+
}
6377

78+
if (file_blobs) {
6479
let toast = Toastify({
6580
text: `⏳${t("file_uploading")} 0%`,
6681
duration: -1,
6782
gravity: "top",
6883
position: 'center',
6984
backgroundColor: '#1565c0',
7085
});
71-
if (files.length > 0) toast.showToast();
86+
toast.showToast();
7287
state.CurrentSession.send_buffer(
73-
new Blob([
74-
serialize_json(msg),
75-
...files.map((file: File) => serialize_file(file, 'value'))
76-
], {type: 'application/octet-stream'}),
88+
new Blob([serialize_json(msg), ...file_blobs], {type: 'application/octet-stream'}),
7789
(loaded: number, total: number) => {
7890
toast.toastElement.innerText = `⏳${t("file_uploading")} ${((loaded / total)*100).toFixed(2)}%`;
7991
if (total - loaded < 100) toast.hideToast();
8092
}
8193
);
82-
8394
} else {
8495
state.CurrentSession.send_message(msg);
8596
}

0 commit comments

Comments
 (0)