func requestHandler(ctx *fasthttp.RequestCtx) { h := &ctx.Request.Header if !ctx.IsGet() { ctx.Error("Method not allowed", fasthttp.StatusMethodNotAllowed) return } if string(ctx.RequestURI()) == *statsRequestPath { var w bytes.Buffer stats.WriteToStream(&w) ctx.Success("text/plain", w.Bytes()) return } if len(h.Peek("If-None-Match")) > 0 { resp := &ctx.Response resp.SetStatusCode(fasthttp.StatusNotModified) resp.Header.Set("Etag", "W/\"CacheForever\"") atomic.AddInt64(&stats.IfNoneMatchHitsCount, 1) return } v := keyPool.Get() if v == nil { v = make([]byte, 128) } key := v.([]byte) key = append(key[:0], getRequestHost(h)...) key = append(key, ctx.RequestURI()...) item, err := cache.GetDeItem(key, time.Second) if err != nil { if err != ybc.ErrCacheMiss { logFatal("Unexpected error when obtaining cache value by key=[%s]: [%s]", key, err) } atomic.AddInt64(&stats.CacheMissesCount, 1) item = fetchFromUpstream(h, key) if item == nil { ctx.Error("Service unavailable", fasthttp.StatusServiceUnavailable) return } } else { atomic.AddInt64(&stats.CacheHitsCount, 1) } defer item.Close() keyPool.Put(v) contentType, err := loadContentType(h, item) if err != nil { ctx.Error("Internal Server Error", fasthttp.StatusInternalServerError) return } rh := &ctx.Response.Header rh.Set("Etag", "W/\"CacheForever\"") rh.Set("Cache-Control", "public, max-age=31536000") buf := item.Value() buf = buf[len(buf)-item.Available():] ctx.Success(contentType, buf) atomic.AddInt64(&stats.BytesSentToClients, int64(len(buf))) }
// Test 6: Plaintext func plaintextHandler(ctx *fasthttp.RequestCtx) { ctx.Success("text/plain", helloWorldBytes) }