diff --git a/html/system.html b/html/system.html index 9c07fdc1..f538d3ee 100644 --- a/html/system.html +++ b/html/system.html @@ -88,6 +88,8 @@


Be careful when entering console commands, you can lock yourself out!
+
+

 
     
 
diff --git a/html/system.js b/html/system.js
index f9fd37eb..c52acd03 100644
--- a/html/system.js
+++ b/html/system.js
@@ -35,14 +35,28 @@ async function ipSub() {
 }
 
 async function cmdSub() {
-  var cmd = document.getElementById('console_cmd').value;
+  const input = document.getElementById('console_cmd');
+  const out = document.getElementById('console_out');
+  const cmd = input.value;
   try {
     const response = await fetch('/cmd', {
       method: 'POST',
       body: cmd
     });
-    console.log('Completed!', response);
+    if (response.status == 401) {
+      window.location.href = 'login.html';
+      return;
+    }
+    let text = await response.text();
+    if (text != "" && !text.endsWith("\n"))
+      text += "\n";
+    if (out.textContent.length > 20000)
+      out.textContent = out.textContent.slice(-16000);
+    out.textContent += "> " + cmd + "\n" + text;
+    out.scrollTop = out.scrollHeight;
+    input.value = "";
   } catch(err) {
+      out.textContent += "> " + cmd + "\n" + err + "\n";
       console.error(`Error: ${err}`);
   }
 }
diff --git a/httpd/httpd.c b/httpd/httpd.c
index 4537eefe..7c0542b2 100644
--- a/httpd/httpd.c
+++ b/httpd/httpd.c
@@ -21,6 +21,7 @@
 
 extern volatile __xdata uint8_t sfr_data[4];
 extern volatile __xdata uint32_t ticks;
+extern __xdata uint8_t cmd_capture;	/* owned by rtlplayground.c, see write_char_no_syslog() */
 extern __code uint8_t * __code hex;
 extern __code struct f_data f_data[];
 extern __code char * __code mime_strings[];
@@ -625,12 +626,29 @@ static void handle_firmware_fragment(__xdata uint8_t *p)
 
 static void run_cmd_body(__xdata uint8_t *body)
 {
+	uint16_t hdr_len = strtox(outbuf, HTTP_RESPONCE_TXT);
+
+	slen = hdr_len;
+	cmd_capture = 1;
 	execute_commands(body);
+	if (cmd_capture == 2)
+		slen += strtox(outbuf + slen, CMD_TRUNCATED);
+	cmd_capture = 0;
+	/* Commands that configure something print nothing at all. Saying
+	 * so beats an empty body, which reads the same as "nothing ran".
+	 * Only on success: a silent failure must not answer with "OK". */
+	if (err_status == ERR_OK && slen == hdr_len)
+		slen += strtox(outbuf + slen, "OK\n");
+	/* On a parse error keep what the parser printed, because that text
+	 * is the explanation, and only restate the status. "400 NO" is as
+	 * long as "200 OK", so the header does not have to be rebuilt. */
 	if (err_status != ERR_OK) {
-		send_bad_request();
-		return;
+		outbuf[9] = '4';
+		outbuf[10] = '0';
+		outbuf[11] = '0';
+		outbuf[13] = 'N';
+		outbuf[14] = 'O';
 	}
-	send_ok();
 }
 
 
diff --git a/httpd/page_impl.c b/httpd/page_impl.c
index 695a6291..8c10572f 100644
--- a/httpd/page_impl.c
+++ b/httpd/page_impl.c
@@ -48,7 +48,7 @@ extern __xdata char sfp_module_serial[2][17];
 extern __xdata uint8_t sfp_options[2];
 
 __code uint8_t * __code HTTP_RESPONCE_JSON = "HTTP/1.1 200 OK\r\nConnection: close\r\nContent-Type: application/json\r\n\r\n";
-__code uint8_t * __code HTTP_RESPONCE_TXT = "HTTP/1.1 200 OK\r\nContent-Type: text/plain\r\n\r\n";
+__code uint8_t * __code HTTP_RESPONCE_TXT = "HTTP/1.1 200 OK\r\nConnection: close\r\nContent-Type: text/plain\r\n\r\n";
 
 // Convert uint8_t to ascii HEX char push on html-buffer.
 void charhex_to_html(char c)
diff --git a/httpd/page_impl.h b/httpd/page_impl.h
index 31a6e08d..cad4cd6f 100644
--- a/httpd/page_impl.h
+++ b/httpd/page_impl.h
@@ -3,6 +3,8 @@
 
 #include 
 
+extern __code uint8_t * __code HTTP_RESPONCE_TXT;
+
 bool send_counters(uint8_t phys_port);
 void send_status(void);
 void send_vlan(uint16_t vlan);
diff --git a/rtl837x_common.h b/rtl837x_common.h
index 83b0ea13..0d4ccc01 100644
--- a/rtl837x_common.h
+++ b/rtl837x_common.h
@@ -37,6 +37,10 @@ extern __xdata uint8_t sbuf[SBUF_SIZE];
 // Size of the TCP Output buffer
 #define TCP_OUTBUF_SIZE 2500
 
+// Appended when a captured command wrote more than the output buffer holds,
+// so a clipped listing is visibly clipped instead of silently short.
+#define CMD_TRUNCATED "\n[output truncated]\n"
+
 // Size of the port name, including the terminating null byte
 #define PORT_NAME_SIZE 32
 
diff --git a/rtlplayground.c b/rtlplayground.c
index 2766501d..b3710c76 100644
--- a/rtlplayground.c
+++ b/rtlplayground.c
@@ -240,8 +240,25 @@ void isr_serial(void) __interrupt(4)
 }
 
 
+/* Set by the httpd while it runs a command that arrived over the network, so
+ * that everything the command prints lands in the response as well. */
+__xdata uint8_t cmd_capture;
+extern __xdata uint8_t outbuf[TCP_OUTBUF_SIZE];
+extern __xdata uint16_t slen;
+
 void write_char_no_syslog(char c)
 {
+	/* Capturing sits here rather than in write_char() so that the messages
+	 * printed through print_string_no_syslog() are captured too: those are
+	 * the replies of the syslog commands, which must not generate a syslog
+	 * packet but do belong in the answer to a command sent over HTTP. */
+	if (cmd_capture) {
+		if (slen < TCP_OUTBUF_SIZE - sizeof(CMD_TRUNCATED))
+			outbuf[slen++] = c;
+		else
+			cmd_capture = 2;	/* out of room, httpd says so */
+	}
+
 	do {
 	} while (tx_buf_empty == 0);
 	if (c =='\n') {