[tor-commits] [meek/master] Refactoring WebExtension native component.
dcf at torproject.org
dcf at torproject.org
Wed Aug 28 05:59:18 UTC 2019
commit a44d297faa806ad79ee7d38d488bd02eeac8ca84
Author: David Fifield <david at bamsoftware.com>
Date: Sat Mar 30 12:11:55 2019 -0600
Refactoring WebExtension native component.
---
webextension/native/endian_386.go | 2 +-
webextension/native/endian_amd64.go | 2 +-
webextension/native/main.go | 77 +++++++++++++++++++++----------------
3 files changed, 45 insertions(+), 36 deletions(-)
diff --git a/webextension/native/endian_386.go b/webextension/native/endian_386.go
index 6a1e44e..af343d7 100644
--- a/webextension/native/endian_386.go
+++ b/webextension/native/endian_386.go
@@ -5,4 +5,4 @@ package main
import "encoding/binary"
-var NativeEndian = binary.LittleEndian
+var nativeEndian = binary.LittleEndian
diff --git a/webextension/native/endian_amd64.go b/webextension/native/endian_amd64.go
index 6a1e44e..af343d7 100644
--- a/webextension/native/endian_amd64.go
+++ b/webextension/native/endian_amd64.go
@@ -5,4 +5,4 @@ package main
import "encoding/binary"
-var NativeEndian = binary.LittleEndian
+var nativeEndian = binary.LittleEndian
diff --git a/webextension/native/main.go b/webextension/native/main.go
index e5f3a74..8771b72 100644
--- a/webextension/native/main.go
+++ b/webextension/native/main.go
@@ -2,7 +2,13 @@
// purpose is to open a localhost TCP socket for communication with meek-client
// in its --helper mode (the WebExtension cannot open a socket on its own). This
// program is also in charge of multiplexing the many incoming socket
-// connections over the single shared stdio stream to/from the WebExtension.
+// connections over the single shared stdio stream to/from the browser.
+//
+// This program does minimal syntax checking. Apart from ensuring that the
+// messages are well-formed JSON with the correct top-level properties, and
+// inspecting the ID, it doesn't care about the contents of messages. It's the
+// responsibility of the browser half of the WebExtension to check everything
+// else.
package main
@@ -44,14 +50,15 @@ const (
maxWebExtensionMessageLength = 1000000
)
-// We receive multiple (possibly concurrent) connections over our listening
-// socket, and we must multiplex all their requests/responses to/from the
-// browser over the single shared stdio stream. When roundTrip sends a
-// webExtensionRoundTripRequest to the browser, creates a channel to receive the
-// response, and stores the ID–channel mapping in requestResponseMap. When
-// inFromBrowserLoop receives a webExtensionRoundTripResponse from the browser,
-// it is tagged with the same ID as the corresponding request. inFromBrowserLoop
-// looks up the matching channel and sends the response over it.
+// We receive multiple (possibly concurrent) connections over the listening
+// socket, and we must multiplex all their requests/results over the single
+// shared stdio stream to the browser. When roundTrip sends a request to the
+// browser, it tags the request with a random ID, creates a channel on which to
+// receive the result, and stores the ID–channel mapping in requestResponseMap.
+// When inFromBrowserLoop receives a webExtensionRoundTripResponse from the
+// browser, it will be tagged with an ID. inFromBrowserLoop looks up the channel
+// in requestResponseMap using the ID, and sends the result back on the channel
+// it finds.
var requestResponseMap = make(map[string]chan<- responseSpec)
var requestResponseMapLock sync.Mutex
@@ -84,13 +91,14 @@ type webExtensionRoundTripResponse struct {
Response responseSpec `json:"response"`
}
-// Read a requestSpec (receive from "meek-client --helper").
+// Receive a requestSpec (from "meek-client --helper").
//
// The meek-client protocol is coincidentally similar to the WebExtension stdio
-// protocol: a 4-byte length, followed by a JSON object of that length. The only
-// difference is the byte order of the length: meek-client's is big-endian,
-// while WebExtension's is native-endian.
-func readRequestSpec(r io.Reader) (requestSpec, error) {
+// protocol: a 4-byte length, followed by a JSON object of that length. The main
+// differences are the byte order of the length prefix—meek-client's is
+// big-endian, while WebExtension's is native-endian—and that meek-client only
+// sends/receives one object per connection.
+func recvRequestSpec(r io.Reader) (requestSpec, error) {
var length uint32
err := binary.Read(r, binary.BigEndian, &length)
if err != nil {
@@ -106,8 +114,8 @@ func readRequestSpec(r io.Reader) (requestSpec, error) {
return nil, err
}
- spec := new(requestSpec)
- err = json.Unmarshal(encodedSpec, spec)
+ var spec requestSpec
+ err = json.Unmarshal(encodedSpec, &spec)
if err != nil {
return nil, err
}
@@ -115,13 +123,12 @@ func readRequestSpec(r io.Reader) (requestSpec, error) {
return spec, nil
}
-// Write a responseSpec (send to "meek-client --helper").
-func writeResponseSpec(w io.Writer, spec responseSpec) error {
+// Send a responseSpec (to "meek-client --helper").
+func sendResponseSpec(w io.Writer, spec responseSpec) error {
encodedSpec, err := json.Marshal(spec)
if err != nil {
panic(err)
}
-
// len returns int, which is specified to be either 32 or 64 bits, so it
// will never be truncated when converting to uint64.
// https://golang.org/ref/spec#Numeric_types
@@ -133,7 +140,6 @@ func writeResponseSpec(w io.Writer, spec responseSpec) error {
if err != nil {
return err
}
-
_, err = w.Write(encodedSpec)
return err
}
@@ -142,7 +148,7 @@ func writeResponseSpec(w io.Writer, spec responseSpec) error {
// https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/Native_messaging#App_side
func recvWebExtensionMessage(r io.Reader) ([]byte, error) {
var length uint32
- err := binary.Read(r, NativeEndian, &length)
+ err := binary.Read(r, nativeEndian, &length)
if err != nil {
return nil, err
}
@@ -167,7 +173,7 @@ func sendWebExtensionMessage(w io.Writer, message []byte) error {
if uint64(length) > math.MaxUint32 {
return fmt.Errorf("WebExtension message is too long to represent: %d", length)
}
- err := binary.Write(w, NativeEndian, uint32(length))
+ err := binary.Write(w, nativeEndian, uint32(length))
if err != nil {
return err
}
@@ -242,17 +248,20 @@ type errorResponseSpec struct {
func handleConn(conn net.Conn, outToBrowserChan chan<- []byte) error {
defer conn.Close()
+ // Read and decode the request from the socket.
err := conn.SetReadDeadline(time.Now().Add(localReadTimeout))
if err != nil {
return err
}
- req, err := readRequestSpec(conn)
+ req, err := recvRequestSpec(conn)
if err != nil {
return err
}
+ // Pass the parameters to the browser and get the result.
resp, err := roundTrip(req, outToBrowserChan)
if err != nil {
+ // In case of error in roundTrip, cook up an error response.
resp = &errorResponseSpec{Error: err.Error()}
}
@@ -261,7 +270,7 @@ func handleConn(conn net.Conn, outToBrowserChan chan<- []byte) error {
if err != nil {
return err
}
- return writeResponseSpec(conn, resp)
+ return sendResponseSpec(conn, resp)
}
// Receive socket connections and dispatch them to handleConn.
@@ -306,15 +315,15 @@ func inFromBrowserLoop() error {
delete(requestResponseMap, resp.ID)
requestResponseMapLock.Unlock()
- if !ok {
- // Either the browser made up an ID that we never sent
- // it, or (more likely) it took too long and roundTrip
- // stopped waiting. Just drop the response on the floor.
- continue
+ if ok {
+ responseSpecChan <- resp.Response
+ // Each socket Conn is good for one request–response exchange only.
+ close(responseSpecChan)
}
- responseSpecChan <- resp.Response
- // Each socket Conn is good for one request–response exchange only.
- close(responseSpecChan)
+ // If !ok, it means that either the browser made up an ID that
+ // we never sent it, or (more likely) it took too long and
+ // roundTrip stopped waiting. In this case there's nothing to
+ // do.
}
}
@@ -356,7 +365,7 @@ func main() {
go func() {
err := inFromBrowserLoop()
if err == io.EOF {
- // EOF is not an error.
+ // EOF is not an error to display.
err = nil
}
errChan <- err
@@ -376,7 +385,7 @@ func main() {
outToBrowserChan <- message
// We quit when we receive a SIGTERM, or when our stdin is closed, or
- // some irrecoverable error happens.
+ // some unrecoverable error happens.
// https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/Native_messaging#Closing_the_native_app
signal.Notify(signalChan, syscall.SIGTERM)
select {
More information about the tor-commits
mailing list