MCPcopy Index your code
hub / github.com/coder/coder / compress

Method compress

coderd/cachecompress/compress.go:281–343  ·  view source on GitHub ↗
(ctx context.Context, encoding string, cref ref, r *http.Request)

Source from the content-addressed store, hash-verified

279}
280
281func (c *Compressor) compress(ctx context.Context, encoding string, cref ref, r *http.Request) {
282 cachePath := cref.key.filePath(c.cacheDir)
283 var err error
284 // we want to handle closing either cref.done or cref.err in a defer at the bottom of the stack so that the encoder
285 // and cache file are both closed first (higher in the defer stack). This prevents data races where waiting HTTP
286 // handlers start reading the file before all the data has been flushed.
287 defer func() {
288 if err != nil {
289 if rErr := os.Remove(cachePath); rErr != nil {
290 // nolint: gocritic // best effort, just debug log any errors
291 c.logger.Debug(ctx, "failed to remove cache file",
292 slog.F("main_err", err), slog.F("remove_err", rErr), slog.F("cache_path", cachePath))
293 }
294 c.mu.Lock()
295 delete(c.cache, cref.key)
296 c.mu.Unlock()
297 close(cref.err)
298 return
299 }
300 close(cref.done)
301 }()
302
303 cacheDir := filepath.Dir(cachePath)
304 err = os.MkdirAll(cacheDir, 0o700)
305 if err != nil {
306 c.logger.Error(ctx, "failed to create cache directory", slog.F("cache_dir", cacheDir))
307 return
308 }
309
310 // We will truncate and overwrite any existing files. This is important in the case that we get restarted
311 // with the same cache dir, possibly with different source files.
312 cacheFile, err := os.OpenFile(cachePath, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0o600)
313 if err != nil {
314 c.logger.Error(ctx, "failed to open compression cache file",
315 slog.F("path", cachePath), slog.Error(err))
316 return
317 }
318 defer cacheFile.Close()
319 encoder, cleanup := c.getEncoder(encoding, cacheFile)
320 if encoder == nil {
321 // can only hit this if there is a programming error
322 c.logger.Critical(ctx, "got nil encoder", slog.F("encoding", encoding))
323 err = xerrors.New("nil encoder")
324 return
325 }
326 defer cleanup()
327 defer encoder.Close() // ensures we flush, needs to be called before cleanup(), so we defer after it.
328
329 cw := &compressResponseWriter{
330 w: encoder,
331 headers: make(http.Header), // ignored
332 }
333 http.FileServer(c.orig).ServeHTTP(cw, r)
334 if cw.code != http.StatusOK {
335 // log at debug because this is likely just a 404
336 c.logger.Debug(ctx, "file server failed to serve",
337 slog.F("encoding", encoding), slog.F("url_path", cref.key.urlPath), slog.F("http_code", cw.code))
338 // mark the error so that we clean up correctly

Callers 1

getRefMethod · 0.95

Calls 11

getEncoderMethod · 0.95
cleanupFunction · 0.85
filePathMethod · 0.80
MkdirAllMethod · 0.80
RemoveMethod · 0.65
CloseMethod · 0.65
NewMethod · 0.65
LockMethod · 0.45
UnlockMethod · 0.45
ErrorMethod · 0.45
ServeHTTPMethod · 0.45

Tested by

no test coverage detected