Skip to content

Commit

Permalink
perf: use a fastest implementation of for filepath.Abs instead
Browse files Browse the repository at this point in the history
  • Loading branch information
dunglas committed Nov 12, 2024
1 parent bc75c15 commit b986987
Show file tree
Hide file tree
Showing 8 changed files with 54 additions and 24 deletions.
2 changes: 1 addition & 1 deletion caddy/caddy.go
Original file line number Diff line number Diff line change
Expand Up @@ -270,7 +270,7 @@ func (f *FrankenPHPModule) Provision(ctx caddy.Context) error {
}

if !needReplacement(f.Root) {
root, err := filepath.Abs(f.Root)
root, err := frankenphp.FastAbs(f.Root)
if err != nil {
return fmt.Errorf("unable to make the root path absolute: %w", err)
}
Expand Down
25 changes: 25 additions & 0 deletions filepath_unix.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package frankenphp

import (
"os"
"path/filepath"
)

// FastAbs is an optimized version of filepath.Abs for Unix systems,
// since we don't expect the working directory to ever change once
// Caddy is running. Avoid the os.Getwd() syscall overhead.
//
// This function is INTERNAL and must not be used outside of this package.
func FastAbs(path string) (string, error) {
if filepath.IsAbs(path) {
return filepath.Clean(path), nil
}

if wderr != nil {
return "", wderr
}

return filepath.Join(wd, path), nil
}

var wd, wderr = os.Getwd()
13 changes: 13 additions & 0 deletions filepath_windows.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package frankenphp

import (
"path/filepath"
)

// FastAbs can't be optimized on Windows because the
// syscall.FullPath function takes an input.
//
// This function is INTERNAL and must not be used outside of this package.
func FastAbs(path string) (string, error) {
return filepath.Abs(path)
}
3 changes: 2 additions & 1 deletion frankenphp_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -921,12 +921,13 @@ func testRejectInvalidHeaders(t *testing.T, opts *testOptions) {
// To run this fuzzing test use: go test -fuzz FuzzRequest
// TODO: Cover more potential cases
func FuzzRequest(f *testing.F) {
absPath, _ := filepath.Abs("./testdata/")

f.Add("hello world")
f.Add("😀😅🙃🤩🥲🤪😘😇😉🐘🧟")
f.Add("%00%11%%22%%33%%44%%55%%66%%77%%88%%99%%aa%%bb%%cc%%dd%%ee%%ff")
f.Add("\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f")
f.Fuzz(func(t *testing.T, fuzzedString string) {
absPath, _ := filepath.Abs("./testdata/")
runTest(t, func(handler func(http.ResponseWriter, *http.Request), _ *httptest.Server, _ int) {
req := httptest.NewRequest("GET", "http://example.com/server-variable", nil)
req.URL = &url.URL{RawQuery: "test=" + fuzzedString, Path: "/server-variable.php/" + fuzzedString}
Expand Down
3 changes: 2 additions & 1 deletion internal/watcher/watch_pattern.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
package watcher

import (
"github.com/dunglas/frankenphp"
"path/filepath"
"strings"

Expand Down Expand Up @@ -34,7 +35,7 @@ func parseFilePattern(filePattern string) (*watchPattern, error) {
w := &watchPattern{}

// first we clean the pattern
absPattern, err := filepath.Abs(filePattern)
absPattern, err := frankenphp.FastAbs(filePattern)
if err != nil {
return nil, err
}
Expand Down
3 changes: 1 addition & 2 deletions metrics.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package frankenphp

import (
"path/filepath"
"regexp"
"sync"
"time"
Expand Down Expand Up @@ -126,7 +125,7 @@ func (m *PrometheusMetrics) StopWorker(name string, reason StopReason) {
}

func (m *PrometheusMetrics) getIdentity(name string) (string, error) {
actualName, err := filepath.Abs(name)
actualName, err := FastAbs(name)
if err != nil {
return name, err
}
Expand Down
27 changes: 9 additions & 18 deletions request_options.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,13 @@ package frankenphp

import (
"path/filepath"
"sync"

"go.uber.org/zap"
)

// RequestOption instances allow to configure a FrankenPHP Request.
type RequestOption func(h *FrankenPHPContext) error

var documentRootCache sync.Map

// WithRequestDocumentRoot sets the root directory of the PHP application.
// if resolveSymlink is true, oath declared as root directory will be resolved
// to its absolute value after the evaluation of any symbolic links.
Expand All @@ -21,25 +18,19 @@ var documentRootCache sync.Map
// directive will set $_SERVER['DOCUMENT_ROOT'] to the real directory path.
func WithRequestDocumentRoot(documentRoot string, resolveSymlink bool) RequestOption {
return func(o *FrankenPHPContext) error {
v, ok := documentRootCache.Load(documentRoot)
if !ok {
var err error
// make sure file root is absolute
v, err = filepath.Abs(documentRoot)
if err != nil {
return err
}
// make sure file root is absolute
root, err := FastAbs(documentRoot)
if err != nil {
return err
}

if resolveSymlink {
if v, err = filepath.EvalSymlinks(v.(string)); err != nil {
return err
}
if resolveSymlink {
if root, err = filepath.EvalSymlinks(root); err != nil {
return err
}

documentRootCache.LoadOrStore(documentRoot, v)
}

o.documentRoot = v.(string)
o.documentRoot = root

return nil
}
Expand Down
2 changes: 1 addition & 1 deletion worker.go
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ func initWorkers(opt []workerOpt) error {
}

func newWorker(o workerOpt) (*worker, error) {
absFileName, err := filepath.Abs(o.fileName)
absFileName, err := FastAbs(o.fileName)
if err != nil {
return nil, fmt.Errorf("worker filename is invalid %q: %w", o.fileName, err)
}
Expand Down

0 comments on commit b986987

Please sign in to comment.