/ gcf.go
gcf.go
 1  // Code from https://github.com/gofiber/recipes/blob/master/gcloud/functions.go
 2  // Copyright by https://github.com/alvarowolfx and https://github.com/Fenny
 3  
 4  package main
 5  
 6  import (
 7  	"bytes"
 8  	"context"
 9  	"fmt"
10  	"io"
11  	"io/ioutil"
12  	"log"
13  	"net"
14  	"net/http"
15  	"strings"
16  
17  	"github.com/gofiber/fiber/v2"
18  	"github.com/valyala/fasthttp/fasthttputil"
19  )
20  
21  // CloudFunctionRouteToFiber route cloud function http.Handler to *fiber.App
22  // Internally, google calls the function with the /execute base URL
23  func CloudFunctionRouteToFiber(fiberApp *fiber.App, w http.ResponseWriter, r *http.Request) error {
24  	return RouteToFiber(fiberApp, w, r, "/execute")
25  }
26  
27  // RouteToFiber route http.Handler to *fiber.App
28  func RouteToFiber(fiberApp *fiber.App, w http.ResponseWriter, r *http.Request, rootURL ...string) error {
29  	ln := fasthttputil.NewInmemoryListener()
30  	defer ln.Close()
31  
32  	// Copy request
33  	body, err := ioutil.ReadAll(r.Body)
34  	if err != nil {
35  		return err
36  	}
37  
38  	url := fmt.Sprintf("%s://%s%s", "http", "0.0.0.0", r.RequestURI)
39  	if len(rootURL) > 0 {
40  		url = strings.Replace(url, rootURL[0], "", -1)
41  	}
42  
43  	proxyReq, err := http.NewRequest(r.Method, url, bytes.NewReader(body))
44  	proxyReq.Header = r.Header
45  
46  	// Create http client
47  	client := http.Client{
48  		Transport: &http.Transport{
49  			DialContext: func(ctx context.Context, network, addr string) (net.Conn, error) {
50  				return ln.Dial()
51  			},
52  		},
53  	}
54  
55  	// Serve request to internal HTTP client
56  	go func() {
57  		log.Fatal(fiberApp.Listener(ln))
58  	}()
59  
60  	// Call internal Fiber API
61  	response, err := client.Do(proxyReq)
62  	if err != nil {
63  		return err
64  	}
65  
66  	// Copy response and headers
67  	for k, values := range response.Header {
68  		for _, v := range values {
69  			w.Header().Set(k, v)
70  		}
71  	}
72  	w.WriteHeader(response.StatusCode)
73  
74  	io.Copy(w, response.Body)
75  	response.Body.Close()
76  
77  	return nil
78  }