| 86 | } |
| 87 | |
| 88 | func New(opts *Options) (*Handler, error) { |
| 89 | if opts.AppearanceFetcher == nil { |
| 90 | daf := atomic.Pointer[appearance.Fetcher]{} |
| 91 | f := appearance.NewDefaultFetcher(opts.DocsURL) |
| 92 | daf.Store(&f) |
| 93 | opts.AppearanceFetcher = &daf |
| 94 | } |
| 95 | handler := &Handler{ |
| 96 | opts: opts, |
| 97 | secureHeaders: secureHeaders(), |
| 98 | Entitlements: opts.Entitlements, |
| 99 | } |
| 100 | |
| 101 | // html files are handled by a text/template. Non-html files |
| 102 | // are served by the default file server. |
| 103 | var err error |
| 104 | handler.htmlTemplates, err = findAndParseHTMLFiles(opts.SiteFS) |
| 105 | if err != nil { |
| 106 | return nil, xerrors.Errorf("failed to parse html files: %w", err) |
| 107 | } |
| 108 | |
| 109 | binHand, err := newBinHandler(opts) |
| 110 | if err != nil { |
| 111 | return nil, xerrors.Errorf("create bin handler: %w", err) |
| 112 | } |
| 113 | |
| 114 | mux := http.NewServeMux() |
| 115 | mux.Handle("/bin/", binHand) |
| 116 | mux.Handle("/", http.FileServer( |
| 117 | http.FS( |
| 118 | // OnlyFiles is a wrapper around the file system that prevents directory |
| 119 | // listings. Directory listings are not required for the site file system, so we |
| 120 | // exclude it as a security measure. In practice, this file system comes from our |
| 121 | // open source code base, but this is considered a best practice for serving |
| 122 | // static files. |
| 123 | OnlyFiles(opts.SiteFS))), |
| 124 | ) |
| 125 | buildInfoResponse, err := json.Marshal(opts.BuildInfo) |
| 126 | if err != nil { |
| 127 | return nil, xerrors.Errorf("failed to marshal build info: %w", err) |
| 128 | } |
| 129 | handler.buildInfoJSON = html.EscapeString(string(buildInfoResponse)) |
| 130 | handler.handler = mux.ServeHTTP |
| 131 | |
| 132 | handler.installScript, err = parseInstallScript(opts.SiteFS, opts.BuildInfo) |
| 133 | if err != nil { |
| 134 | opts.Logger.Warn(context.Background(), "could not parse install.sh, it will be unavailable", slog.Error(err)) |
| 135 | } |
| 136 | |
| 137 | return handler, nil |
| 138 | } |
| 139 | |
| 140 | type Handler struct { |
| 141 | opts *Options |