Skip to content

Commit 227d80d

Browse files
authored
Merge pull request #2831 from kemalturk/firebase-functions-improvement
Refactored HTTP routing to use fasthttp directly
2 parents 13bbadb + e709bed commit 227d80d

File tree

2 files changed

+101
-116
lines changed

2 files changed

+101
-116
lines changed

firebase-functions/README.md

Lines changed: 56 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -205,81 +205,73 @@ In `functions.go`, convert Google Cloud Function requests to Fiber and route the
205205
package app
206206

207207
import (
208-
"bytes"
209-
"context"
210-
"fmt"
211-
"io"
212-
"log"
213-
"net"
214-
"net/http"
215-
"strings"
208+
"io"
209+
"net"
210+
"net/http"
216211

217-
"github.com/gofiber/fiber/v2"
218-
"github.com/valyala/fasthttp/fasthttputil"
212+
"github.com/gofiber/fiber/v2"
213+
"github.com/gofiber/fiber/v2/utils"
214+
"github.com/valyala/fasthttp"
219215
)
220216

221217
// CloudFunctionRouteToFiber route cloud function http.Handler to *fiber.App
222218
// Internally, google calls the function with the /execute base URL
223219
func CloudFunctionRouteToFiber(fiberApp *fiber.App, w http.ResponseWriter, r *http.Request) error {
224-
return RouteToFiber(fiberApp, w, r, "/execute")
225-
}
226-
227-
// RouteToFiber route http.Handler to *fiber.App
228-
func RouteToFiber(fiberApp *fiber.App, w http.ResponseWriter, r *http.Request, rootURL ...string) error {
229-
ln := fasthttputil.NewInmemoryListener()
230-
defer ln.Close()
231-
232-
// Copy request
233-
body, err := io.ReadAll(r.Body)
234-
if err != nil {
235-
return err
236-
}
237-
238-
url := fmt.Sprintf("%s://%s%s", "http", "0.0.0.0", r.RequestURI)
239-
if len(rootURL) > 0 {
240-
url = strings.Replace(url, rootURL[0], "", -1)
241-
}
242-
243-
proxyReq, err := http.NewRequest(r.Method, url, bytes.NewReader(body))
244-
245-
if err != nil {
246-
return err
247-
}
248-
249-
proxyReq.Header = r.Header
250220

251-
// Create http client
252-
client := http.Client{
253-
Transport: &http.Transport{
254-
DialContext: func(ctx context.Context, network, addr string) (net.Conn, error) {
255-
return ln.Dial()
256-
},
257-
},
258-
}
259-
260-
// Serve request to internal HTTP client
261-
go func() {
262-
log.Fatal(fiberApp.Listener(ln))
263-
}()
221+
// Convert net/http -> fasthttp Ctx
222+
ctx := ConvertNetHTTPRequestToFastHTTPCtx(r, w)
264223

265-
// Call internal Fiber API
266-
response, err := client.Do(proxyReq)
267-
if err != nil {
268-
return err
269-
}
224+
// Run Fiber
225+
fiberApp.Handler()(ctx)
270226

271-
// Copy response and headers
272-
for k, values := range response.Header {
273-
for _, v := range values {
274-
w.Header().Set(k, v)
275-
}
276-
}
277-
w.WriteHeader(response.StatusCode)
227+
// Convert fasthttp Ctx -> net/http
228+
ctx.Response.Header.VisitAll(func(k, v []byte) {
229+
w.Header().Add(string(k), string(v))
230+
})
231+
w.WriteHeader(ctx.Response.StatusCode())
232+
_, err := w.Write(ctx.Response.Body())
278233

279-
io.Copy(w, response.Body)
280-
response.Body.Close()
234+
return err
235+
}
281236

282-
return nil
237+
// ConvertNetHTTPRequestToFastHTTPCtx converts a net/http.Request to fasthttp.RequestCtx
238+
func ConvertNetHTTPRequestToFastHTTPCtx(r *http.Request, w http.ResponseWriter) *fasthttp.RequestCtx {
239+
// New fasthttp request
240+
req := fasthttp.AcquireRequest()
241+
defer fasthttp.ReleaseRequest(req)
242+
// Convert net/http -> fasthttp request
243+
if r.Body != nil {
244+
n, err := io.Copy(req.BodyWriter(), r.Body)
245+
req.Header.SetContentLength(int(n))
246+
247+
if err != nil {
248+
http.Error(w, utils.StatusMessage(fiber.StatusInternalServerError), fiber.StatusInternalServerError)
249+
return nil
250+
}
251+
}
252+
req.Header.SetMethod(r.Method)
253+
req.SetRequestURI(r.RequestURI)
254+
req.SetHost(r.Host)
255+
req.Header.SetHost(r.Host)
256+
for key, val := range r.Header {
257+
for _, v := range val {
258+
req.Header.Set(key, v)
259+
}
260+
}
261+
262+
if _, _, err := net.SplitHostPort(r.RemoteAddr); err != nil && err.(*net.AddrError).Err == "missing port in address" {
263+
r.RemoteAddr = net.JoinHostPort(r.RemoteAddr, "80")
264+
}
265+
remoteAddr, err := net.ResolveTCPAddr("tcp", r.RemoteAddr)
266+
if err != nil {
267+
http.Error(w, utils.StatusMessage(fiber.StatusInternalServerError), fiber.StatusInternalServerError)
268+
return nil
269+
}
270+
271+
var fctx fasthttp.RequestCtx
272+
fctx.Init(req, remoteAddr, nil)
273+
274+
return &fctx
283275
}
284276
```
285277

firebase-functions/functions.go

Lines changed: 45 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -1,78 +1,71 @@
11
package app
22

33
import (
4-
"bytes"
5-
"context"
6-
"fmt"
74
"io"
8-
"log"
95
"net"
106
"net/http"
11-
"strings"
127

138
"github.com/gofiber/fiber/v2"
14-
"github.com/valyala/fasthttp/fasthttputil"
9+
"github.com/gofiber/fiber/v2/utils"
10+
"github.com/valyala/fasthttp"
1511
)
1612

1713
// CloudFunctionRouteToFiber route cloud function http.Handler to *fiber.App
1814
// Internally, google calls the function with the /execute base URL
1915
func CloudFunctionRouteToFiber(fiberApp *fiber.App, w http.ResponseWriter, r *http.Request) error {
20-
return RouteToFiber(fiberApp, w, r, "/execute")
21-
}
2216

23-
// RouteToFiber route http.Handler to *fiber.App
24-
func RouteToFiber(fiberApp *fiber.App, w http.ResponseWriter, r *http.Request, rootURL ...string) error {
25-
ln := fasthttputil.NewInmemoryListener()
26-
defer ln.Close()
17+
// Convert net/http -> fasthttp Ctx
18+
ctx := ConvertNetHTTPRequestToFastHTTPCtx(r, w)
2719

28-
// Copy request
29-
body, err := io.ReadAll(r.Body)
30-
if err != nil {
31-
return err
32-
}
20+
// Run Fiber
21+
fiberApp.Handler()(ctx)
3322

34-
url := fmt.Sprintf("%s://%s%s", "http", "0.0.0.0", r.RequestURI)
35-
if len(rootURL) > 0 {
36-
url = strings.Replace(url, rootURL[0], "", -1)
37-
}
23+
// Convert fasthttp Ctx -> net/http
24+
ctx.Response.Header.VisitAll(func(k, v []byte) {
25+
w.Header().Add(string(k), string(v))
26+
})
27+
w.WriteHeader(ctx.Response.StatusCode())
28+
_, err := w.Write(ctx.Response.Body())
3829

39-
proxyReq, err := http.NewRequest(r.Method, url, bytes.NewReader(body))
40-
if err != nil {
41-
return err
42-
}
30+
return err
31+
}
4332

44-
proxyReq.Header = r.Header
33+
// ConvertNetHTTPRequestToFastHTTPCtx converts a net/http.Request to fasthttp.RequestCtx
34+
func ConvertNetHTTPRequestToFastHTTPCtx(r *http.Request, w http.ResponseWriter) *fasthttp.RequestCtx {
35+
// New fasthttp request
36+
req := fasthttp.AcquireRequest()
37+
defer fasthttp.ReleaseRequest(req)
38+
// Convert net/http -> fasthttp request
39+
if r.Body != nil {
40+
n, err := io.Copy(req.BodyWriter(), r.Body)
41+
req.Header.SetContentLength(int(n))
4542

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-
},
43+
if err != nil {
44+
http.Error(w, utils.StatusMessage(fiber.StatusInternalServerError), fiber.StatusInternalServerError)
45+
return nil
46+
}
5347
}
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
48+
req.Header.SetMethod(r.Method)
49+
req.SetRequestURI(r.RequestURI)
50+
req.SetHost(r.Host)
51+
req.Header.SetHost(r.Host)
52+
for key, val := range r.Header {
53+
for _, v := range val {
54+
req.Header.Set(key, v)
55+
}
6456
}
6557

66-
// Copy response and headers
67-
for k, values := range response.Header {
68-
for _, v := range values {
69-
w.Header().Set(k, v)
70-
}
58+
if _, _, err := net.SplitHostPort(r.RemoteAddr); err != nil && err.(*net.AddrError).Err == "missing port in address" {
59+
r.RemoteAddr = net.JoinHostPort(r.RemoteAddr, "80")
60+
}
61+
remoteAddr, err := net.ResolveTCPAddr("tcp", r.RemoteAddr)
62+
if err != nil {
63+
http.Error(w, utils.StatusMessage(fiber.StatusInternalServerError), fiber.StatusInternalServerError)
64+
return nil
7165
}
72-
w.WriteHeader(response.StatusCode)
7366

74-
io.Copy(w, response.Body)
75-
response.Body.Close()
67+
var fctx fasthttp.RequestCtx
68+
fctx.Init(req, remoteAddr, nil)
7669

77-
return nil
70+
return &fctx
7871
}

0 commit comments

Comments
 (0)