From fb0bfc0807c887f052918ea867fbee566404b7f7 Mon Sep 17 00:00:00 2001 From: Jeff King Date: Wed, 18 Jul 2018 01:08:35 -0400 Subject: [PATCH] native: feed stdin of subprocess for "run" There's currently no way to tell the native messenger to provide a particular stdin to a "run" command. This leads to awkward uses of here-docs, which in turn require hacks like the one in 4a5dcd75576cb218815bf75459b74de657f993ae. Instead, let's take the "content" field from the message body and feed that to the command's stdin, which gives us a more robust channel for passing arbitrary bytes. Note that we have to switch to using subprocess.Popen's communicate() method, which will make sure we don't deadlock if the input or output exceeds a pipe buffer. Note also that when no stdin is provided by the caller (i.e., all current cases), we'll pass an empty string. This actually fixes a minor bug. Because we didn't override the command's stdin argument, it's hooked to the messenger's stdin, which is the pipe coming from firefox. If the command tries to read, it (and the messenger) will hang forever, since firefox is waiting for the messenger to respond before writing anything else. I bumped the native messenger version. This is mostly backwards compatible (existing callers just don't send any stdin content at all). But a caller that wants to send stdin should check to make sure we have at least 0.1.7. --- native/native_main.py | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/native/native_main.py b/native/native_main.py index 5447f6f4..9a20754e 100755 --- a/native/native_main.py +++ b/native/native_main.py @@ -14,7 +14,7 @@ import time import unicodedata DEBUG = False -VERSION = "0.1.6" +VERSION = "0.1.7" class NoConnectionError(Exception): @@ -413,15 +413,14 @@ def handleMessage(message): elif cmd == "run": commands = message["command"] + stdin = message.get("content", "").encode("utf-8") - try: - p = subprocess.check_output(commands, shell=True) - reply["content"] = p.decode("utf-8") - reply["code"] = 0 + p = subprocess.Popen(commands, shell=True, + stdin=subprocess.PIPE, + stdout=subprocess.PIPE) - except subprocess.CalledProcessError as process: - reply["code"] = process.returncode - reply["content"] = process.output.decode("utf-8") + reply["content"] = p.communicate(stdin)[0].decode("utf-8") + reply["code"] = p.returncode elif cmd == "eval": output = eval(message["command"])