mirror of
https://gitlab.torproject.org/tpo/anti-censorship/pluggable-transports/snowflake.git
synced 2025-10-13 11:11:30 -04:00
Encode client-broker messages as json in HTTP body
Send the client poll request and response in a json-encoded format in the HTTP request body rather than sending the data in HTTP headers. This will pave the way for using domain-fronting alternatives for the Snowflake rendezvous.
This commit is contained in:
parent
ae7cc478fd
commit
270eb21803
7 changed files with 472 additions and 63 deletions
107
common/messages/client.go
Normal file
107
common/messages/client.go
Normal file
|
@ -0,0 +1,107 @@
|
|||
//Package for communication with the snowflake broker
|
||||
|
||||
//import "git.torproject.org/pluggable-transports/snowflake.git/common/messages"
|
||||
package messages
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
const ClientVersion = "1.0"
|
||||
|
||||
/* Client--Broker protocol v1.x specification:
|
||||
|
||||
All messages contain the version number
|
||||
followed by a new line and then the message body
|
||||
<message> := <version>\n<body>
|
||||
<version> := <digit>.<digit>
|
||||
<body> := <poll request>|<poll response>
|
||||
|
||||
There are two different types of body messages,
|
||||
each encoded in JSON format
|
||||
|
||||
== ClientPollRequest ==
|
||||
<poll request> :=
|
||||
{
|
||||
offer: <sdp offer>
|
||||
[nat: (unknown|restricted|unrestricted)]
|
||||
}
|
||||
|
||||
The NAT field is optional, and if it is missing a
|
||||
value of "unknown" will be assumed.
|
||||
|
||||
== ClientPollResponse ==
|
||||
<poll response> :=
|
||||
{
|
||||
[answer: <sdp answer>]
|
||||
[error: <error string>]
|
||||
}
|
||||
|
||||
If the broker succeeded in matching the client with a proxy,
|
||||
the answer field MUST contain a valid SDP answer, and the
|
||||
error field MUST be empty. If the answer field is empty, the
|
||||
error field MUST contain a string explaining with a reason
|
||||
for the error.
|
||||
|
||||
*/
|
||||
|
||||
type ClientPollRequest struct {
|
||||
Offer string `json:"offer"`
|
||||
NAT string `json:"nat"`
|
||||
}
|
||||
|
||||
// Encodes a poll message from a snowflake client
|
||||
func (req *ClientPollRequest) EncodePollRequest() ([]byte, error) {
|
||||
body, err := json.Marshal(req)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return append([]byte(ClientVersion+"\n"), body...), nil
|
||||
}
|
||||
|
||||
// Decodes a poll message from a snowflake client
|
||||
func DecodeClientPollRequest(data []byte) (*ClientPollRequest, error) {
|
||||
var message ClientPollRequest
|
||||
|
||||
err := json.Unmarshal(data, &message)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if message.Offer == "" {
|
||||
return nil, fmt.Errorf("no supplied offer")
|
||||
}
|
||||
|
||||
if message.NAT == "" {
|
||||
message.NAT = "unknown"
|
||||
}
|
||||
|
||||
return &message, nil
|
||||
}
|
||||
|
||||
type ClientPollResponse struct {
|
||||
Answer string `json:"answer,omitempty"`
|
||||
Error string `json:"error,omitempty"`
|
||||
}
|
||||
|
||||
// Encodes a poll response for a snowflake client
|
||||
func (resp *ClientPollResponse) EncodePollResponse() ([]byte, error) {
|
||||
return json.Marshal(resp)
|
||||
}
|
||||
|
||||
// Decodes a poll response for a snowflake client
|
||||
// If the Error field is empty, the Answer should be non-empty
|
||||
func DecodeClientPollResponse(data []byte) (*ClientPollResponse, error) {
|
||||
var message ClientPollResponse
|
||||
|
||||
err := json.Unmarshal(data, &message)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if message.Error == "" && message.Answer == "" {
|
||||
return nil, fmt.Errorf("received empty broker response")
|
||||
}
|
||||
|
||||
return &message, nil
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue