Copy appengine directory from meek commit 6057a9e9d6.

This commit is contained in:
David Fifield 2017-07-15 11:48:28 -07:00
parent afe7716903
commit a150a991d0
3 changed files with 168 additions and 0 deletions

31
appengine/README Normal file
View file

@ -0,0 +1,31 @@
This component runs on Google App Engine. It lies between meek-client
and meek-server. The App Engine component receives requests from the
client and forwards them to the server, then receives responses from the
server and forwards them to the client.
You need the Go App Engine SDK in order to deploy the app.
https://cloud.google.com/sdk/docs/#linux
After unpacking, install the app-engine-go component:
google-cloud-sdk/bin/gcloud components install app-engine-go
To test locally, run
google-cloud-sdk/bin/dev_appserver.py app.yaml
The app will be running at http://127.0.0.1:8080/. You can test broker
forwarding function by browsing to http://127.0.0.1:8000/ip.
To deploy to App Engine, first create a new project and app. You have to
think of a unique name (marked as "<appname>" in the commands). You only
have to do the "create" step once; subsequent times you can go straight
to the "deploy" step. This command will open a browser window so you can
log in to a Google account.
google-cloud-sdk/bin/gcloud projects create <appname>
google-cloud-sdk/bin/gcloud app create --project=<appname>
Then to deploy the project, run:
google-cloud-sdk/bin/gcloud app deploy --project=<appname>
To configure meek-client to talk to the App Engine app, provide
"https://<appname>.appspot.com/" as the url and "www.google.com" as the
front domain.
UseBridges 1
Bridge meek 0.0.2.0:1 url=https://example.appspot.com/ front=www.google.com
ClientTransportPlugin meek exec ./meek-client --log meek-client.log

10
appengine/app.yaml Normal file
View file

@ -0,0 +1,10 @@
runtime: go
api_version: go1
automatic_scaling:
max_idle_instances: 2
min_pending_latency: 1000ms
handlers:
- url: /.*
script: _go_app
secure: always

127
appengine/reflect.go Normal file
View file

@ -0,0 +1,127 @@
// A web app for Google App Engine that proxies HTTP requests and responses to a
// Tor relay running meek-server.
package reflect
import (
"io"
"net"
"net/http"
"net/url"
"time"
"appengine"
"appengine/urlfetch"
)
const (
forwardURL = "https://meek.bamsoftware.com/"
// A timeout of 0 means to use the App Engine default (5 seconds).
urlFetchTimeout = 20 * time.Second
)
var context appengine.Context
// Join two URL paths.
func pathJoin(a, b string) string {
if len(a) > 0 && a[len(a)-1] == '/' {
a = a[:len(a)-1]
}
if len(b) == 0 || b[0] != '/' {
b = "/" + b
}
return a + b
}
// We reflect only a whitelisted set of header fields. In requests, the full
// list includes things like User-Agent and X-Appengine-Country that the Tor
// bridge doesn't need to know. In responses, there may be things like
// Transfer-Encoding that interfere with App Engine's own hop-by-hop headers.
var reflectedHeaderFields = []string{
"Content-Type",
"X-Session-Id",
}
// Get the original client IP address as a string. When using the standard
// net/http server, Request.RemoteAddr is a "host:port" string; however App
// Engine seems to use just "host". We check for both to be safe.
func getClientAddr(r *http.Request) string {
host, _, err := net.SplitHostPort(r.RemoteAddr)
if err == nil {
return host
}
return r.RemoteAddr
}
// Make a copy of r, with the URL being changed to be relative to forwardURL,
// and including only the headers in reflectedHeaderFields.
func copyRequest(r *http.Request) (*http.Request, error) {
u, err := url.Parse(forwardURL)
if err != nil {
return nil, err
}
// Append the requested path to the path in forwardURL, so that
// forwardURL can be something like "https://example.com/reflect".
u.Path = pathJoin(u.Path, r.URL.Path)
c, err := http.NewRequest(r.Method, u.String(), r.Body)
if err != nil {
return nil, err
}
for _, key := range reflectedHeaderFields {
values, ok := r.Header[key]
if ok {
for _, value := range values {
c.Header.Add(key, value)
}
}
}
// Set the original client IP address in a Meek-IP header. We would use
// X-Forwarded-For, but App Engine prohibits setting that header:
// https://cloud.google.com/appengine/docs/standard/go/outbound-requests#request_headers
// We could use Forwarded from RFC 7239, but other CDNs already use
// X-Forwarded-For and this way we only need one parser.
c.Header.Add("Meek-IP", getClientAddr(r))
return c, nil
}
func handler(w http.ResponseWriter, r *http.Request) {
context = appengine.NewContext(r)
fr, err := copyRequest(r)
if err != nil {
context.Errorf("copyRequest: %s", err)
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
// Use urlfetch.Transport directly instead of urlfetch.Client because we
// want only a single HTTP transaction, not following redirects.
transport := urlfetch.Transport{
Context: context,
// Despite the name, Transport.Deadline is really a timeout and
// not an absolute deadline as used in the net package. In
// other words it is a time.Duration, not a time.Time.
Deadline: urlFetchTimeout,
}
resp, err := transport.RoundTrip(fr)
if err != nil {
context.Errorf("RoundTrip: %s", err)
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
defer resp.Body.Close()
for _, key := range reflectedHeaderFields {
values, ok := resp.Header[key]
if ok {
for _, value := range values {
w.Header().Add(key, value)
}
}
}
w.WriteHeader(resp.StatusCode)
n, err := io.Copy(w, resp.Body)
if err != nil {
context.Errorf("io.Copy after %d bytes: %s", n, err)
}
}
func init() {
http.HandleFunc("/", handler)
}