Remove Golang reverseproxy and use http Client

Signed-off-by: Alex Ellis <alexellis2@gmail.com>
This commit is contained in:
Alex Ellis
2018-03-03 10:44:54 +00:00
parent 67bda365cd
commit 26e0de3497
5 changed files with 75 additions and 62 deletions

View File

@ -1,9 +1,9 @@
package handlers package handlers
import ( import (
"io"
"log" "log"
"net/http" "net/http"
"net/http/httputil"
"strconv" "strconv"
"strings" "strings"
"time" "time"
@ -14,36 +14,66 @@ import (
) )
// MakeForwardingProxyHandler create a handler which forwards HTTP requests // MakeForwardingProxyHandler create a handler which forwards HTTP requests
func MakeForwardingProxyHandler(proxy *httputil.ReverseProxy, metrics *metrics.MetricOptions) http.HandlerFunc { func MakeForwardingProxyHandler(proxy *types.HttpClientReverseProxy, metrics *metrics.MetricOptions) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) { baseURL := proxy.BaseURL.String()
uri := r.URL.String() if strings.HasSuffix(baseURL, "/") {
baseURL = baseURL[0 : len(baseURL)-1]
}
log.Printf("> Forwarding [%s] to %s", r.Method, r.URL.String()) return func(w http.ResponseWriter, r *http.Request) {
requestURL := r.URL.String()
log.Printf("> Forwarding [%s] to %s", r.Method, requestURL)
start := time.Now() start := time.Now()
writeAdapter := types.NewWriteAdapter(w) upstreamReq, _ := http.NewRequest(r.Method, baseURL+requestURL, nil)
proxy.ServeHTTP(writeAdapter, r)
upstreamReq.Header["X-Forwarded-For"] = []string{r.RequestURI}
if r.Body != nil {
defer r.Body.Close()
upstreamReq.Body = r.Body
}
res, resErr := proxy.Client.Do(upstreamReq)
if resErr != nil {
log.Printf("upstream client error: %s\n", resErr)
return
}
if res.Body != nil {
defer res.Body.Close()
}
for k, v := range res.Header {
w.Header()[k] = v
}
io.CopyBuffer(w, res.Body, nil)
seconds := time.Since(start).Seconds() seconds := time.Since(start).Seconds()
log.Printf("< [%s] - %d took %f seconds\n", r.URL.String(), log.Printf("< [%s] - %d took %f seconds\n", r.URL.String(),
writeAdapter.GetHeaderCode(), seconds) res.StatusCode, seconds)
forward := "/function/" forward := "/function/"
if startsWith(uri, forward) { if startsWith(requestURL, forward) {
// log.Printf("function=%s", uri[len(forward):]) // log.Printf("function=%s", uri[len(forward):])
service := uri[len(forward):] service := requestURL[len(forward):]
metrics.GatewayFunctionsHistogram. metrics.GatewayFunctionsHistogram.
WithLabelValues(service). WithLabelValues(service).
Observe(seconds) Observe(seconds)
code := strconv.Itoa(writeAdapter.GetHeaderCode()) code := strconv.Itoa(res.StatusCode)
metrics.GatewayFunctionInvocation. metrics.GatewayFunctionInvocation.
With(prometheus.Labels{"function_name": service, "code": code}). With(prometheus.Labels{"function_name": service, "code": code}).
Inc() Inc()
} }
} }
} }

View File

@ -48,7 +48,7 @@ func AddMetricsHandler(handler http.HandlerFunc, prometheusQuery PrometheusQuery
err := json.Unmarshal(upstreamBody, &functions) err := json.Unmarshal(upstreamBody, &functions)
if err != nil { if err != nil {
log.Println(err) log.Printf("Metrics upstream error: %s", err)
w.Header().Set("Content-Type", "text/plain") w.Header().Set("Content-Type", "text/plain")
w.WriteHeader(http.StatusInternalServerError) w.WriteHeader(http.StatusInternalServerError)

View File

@ -7,7 +7,6 @@ import (
"fmt" "fmt"
"log" "log"
"net/http" "net/http"
"net/http/httputil"
"time" "time"
"github.com/gorilla/mux" "github.com/gorilla/mux"
@ -41,7 +40,7 @@ func main() {
servicePollInterval := time.Second * 5 servicePollInterval := time.Second * 5
reverseProxy := httputil.NewSingleHostReverseProxy(config.FunctionsProviderURL) reverseProxy := types.NewHttpClientReverseProxy(config.FunctionsProviderURL, config.ReadTimeout)
faasHandlers.Proxy = internalHandlers.MakeForwardingProxyHandler(reverseProxy, &metricsOptions) faasHandlers.Proxy = internalHandlers.MakeForwardingProxyHandler(reverseProxy, &metricsOptions)
faasHandlers.RoutelessProxy = internalHandlers.MakeForwardingProxyHandler(reverseProxy, &metricsOptions) faasHandlers.RoutelessProxy = internalHandlers.MakeForwardingProxyHandler(reverseProxy, &metricsOptions)

View File

@ -1,48 +0,0 @@
// Copyright (c) Alex Ellis 2017. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
package types
import (
"log"
"net/http"
)
// WriteAdapter adapts a ResponseWriter
type WriteAdapter struct {
Writer http.ResponseWriter
HTTPResult *HTTPResult
}
// HTTPResult captures data from forwarded HTTP call
type HTTPResult struct {
HeaderCode int // HeaderCode is the result of WriteHeader(int)
}
//NewWriteAdapter create a new NewWriteAdapter
func NewWriteAdapter(w http.ResponseWriter) WriteAdapter {
return WriteAdapter{Writer: w, HTTPResult: &HTTPResult{}}
}
//Header adapts Header
func (w WriteAdapter) Header() http.Header {
return w.Writer.Header()
}
// Write adapts Write for a straight pass-through
func (w WriteAdapter) Write(data []byte) (int, error) {
return w.Writer.Write(data)
}
// WriteHeader adapts WriteHeader
func (w WriteAdapter) WriteHeader(statusCode int) {
w.Writer.WriteHeader(statusCode)
w.HTTPResult.HeaderCode = statusCode
log.Printf("GetHeaderCode %d", w.HTTPResult.HeaderCode)
}
// GetHeaderCode result from WriteHeader
func (w *WriteAdapter) GetHeaderCode() int {
return w.HTTPResult.HeaderCode
}

View File

@ -0,0 +1,32 @@
package types
import (
"net"
"net/http"
"net/url"
"time"
)
func NewHttpClientReverseProxy(baseURL *url.URL, timeout time.Duration) *HttpClientReverseProxy {
h := HttpClientReverseProxy{
BaseURL: baseURL,
}
h.Client = &http.Client{
Transport: &http.Transport{
Proxy: http.ProxyFromEnvironment,
DialContext: (&net.Dialer{
Timeout: timeout,
KeepAlive: 1 * time.Second,
}).DialContext,
IdleConnTimeout: 120 * time.Millisecond,
ExpectContinueTimeout: 1500 * time.Millisecond,
},
}
return &h
}
type HttpClientReverseProxy struct {
BaseURL *url.URL
Client *http.Client
}