fileserver.go 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120
  1. // Example static file server.
  2. //
  3. // Serves static files from the given directory.
  4. // Exports various stats at /stats .
  5. package main
  6. import (
  7. "expvar"
  8. "flag"
  9. "log"
  10. "github.com/valyala/fasthttp"
  11. "github.com/valyala/fasthttp/expvarhandler"
  12. )
  13. var (
  14. addr = flag.String("addr", "localhost:8080", "TCP address to listen to")
  15. addrTLS = flag.String("addrTLS", "", "TCP address to listen to TLS (aka SSL or HTTPS) requests. Leave empty for disabling TLS")
  16. byteRange = flag.Bool("byteRange", false, "Enables byte range requests if set to true")
  17. certFile = flag.String("certFile", "./ssl-cert.pem", "Path to TLS certificate file")
  18. compress = flag.Bool("compress", false, "Enables transparent response compression if set to true")
  19. dir = flag.String("dir", "/usr/share/nginx/html", "Directory to serve static files from")
  20. generateIndexPages = flag.Bool("generateIndexPages", true, "Whether to generate directory index pages")
  21. keyFile = flag.String("keyFile", "./ssl-cert.key", "Path to TLS key file")
  22. vhost = flag.Bool("vhost", false, "Enables virtual hosting by prepending the requested path with the requested hostname")
  23. )
  24. func main() {
  25. // Parse command-line flags.
  26. flag.Parse()
  27. // Setup FS handler
  28. fs := &fasthttp.FS{
  29. Root: *dir,
  30. IndexNames: []string{"index.html"},
  31. GenerateIndexPages: *generateIndexPages,
  32. Compress: *compress,
  33. AcceptByteRange: *byteRange,
  34. }
  35. if *vhost {
  36. fs.PathRewrite = fasthttp.NewVHostPathRewriter(0)
  37. }
  38. fsHandler := fs.NewRequestHandler()
  39. // Create RequestHandler serving server stats on /stats and files
  40. // on other requested paths.
  41. // /stats output may be filtered using regexps. For example:
  42. //
  43. // * /stats?r=fs will show only stats (expvars) containing 'fs'
  44. // in their names.
  45. requestHandler := func(ctx *fasthttp.RequestCtx) {
  46. switch string(ctx.Path()) {
  47. case "/stats":
  48. expvarhandler.ExpvarHandler(ctx)
  49. default:
  50. fsHandler(ctx)
  51. updateFSCounters(ctx)
  52. }
  53. }
  54. // Start HTTP server.
  55. if len(*addr) > 0 {
  56. log.Printf("Starting HTTP server on %q", *addr)
  57. go func() {
  58. if err := fasthttp.ListenAndServe(*addr, requestHandler); err != nil {
  59. log.Fatalf("error in ListenAndServe: %v", err)
  60. }
  61. }()
  62. }
  63. // Start HTTPS server.
  64. if len(*addrTLS) > 0 {
  65. log.Printf("Starting HTTPS server on %q", *addrTLS)
  66. go func() {
  67. if err := fasthttp.ListenAndServeTLS(*addrTLS, *certFile, *keyFile, requestHandler); err != nil {
  68. log.Fatalf("error in ListenAndServeTLS: %v", err)
  69. }
  70. }()
  71. }
  72. log.Printf("Serving files from directory %q", *dir)
  73. log.Printf("See stats at http://%s/stats", *addr)
  74. // Wait forever.
  75. select {}
  76. }
  77. func updateFSCounters(ctx *fasthttp.RequestCtx) {
  78. // Increment the number of fsHandler calls.
  79. fsCalls.Add(1)
  80. // Update other stats counters
  81. resp := &ctx.Response
  82. switch resp.StatusCode() {
  83. case fasthttp.StatusOK:
  84. fsOKResponses.Add(1)
  85. fsResponseBodyBytes.Add(int64(resp.Header.ContentLength()))
  86. case fasthttp.StatusNotModified:
  87. fsNotModifiedResponses.Add(1)
  88. case fasthttp.StatusNotFound:
  89. fsNotFoundResponses.Add(1)
  90. default:
  91. fsOtherResponses.Add(1)
  92. }
  93. }
  94. // Various counters - see https://pkg.go.dev/expvar for details.
  95. var (
  96. // Counter for total number of fs calls
  97. fsCalls = expvar.NewInt("fsCalls")
  98. // Counters for various response status codes
  99. fsOKResponses = expvar.NewInt("fsOKResponses")
  100. fsNotModifiedResponses = expvar.NewInt("fsNotModifiedResponses")
  101. fsNotFoundResponses = expvar.NewInt("fsNotFoundResponses")
  102. fsOtherResponses = expvar.NewInt("fsOtherResponses")
  103. // Total size in bytes for OK response bodies served.
  104. fsResponseBodyBytes = expvar.NewInt("fsResponseBodyBytes")
  105. )