Path: blob/main/components/openvsx-proxy/pkg/handler.go
2498 views
// Copyright (c) 2021 Gitpod GmbH. All rights reserved.1// Licensed under the GNU Affero General Public License (AGPL).2// See License.AGPL.txt in the project root for license information.34package pkg56import (7"context"8"fmt"9"math/rand"10"net/http"11"net/http/httputil"12"strconv"13"time"1415"github.com/gitpod-io/gitpod/common-go/log"16"github.com/google/uuid"17"github.com/sirupsen/logrus"18)1920func (o *OpenVSXProxy) Handler(p *httputil.ReverseProxy) func(http.ResponseWriter, *http.Request) {21return func(rw http.ResponseWriter, r *http.Request) {22start := time.Now()2324var (25hitCacheRegular = false26hitCacheBackup = false27)2829reqid := ""30uuid, err := uuid.NewRandom()31if err != nil {32log.WithError(err).Warn("cannot generate a UUID")33reqid = fmt.Sprintf("req%d", rand.Intn(999999))34} else {35reqid = uuid.String()36}3738logFields := logrus.Fields{39LOG_FIELD_FUNC: "request_handler",40LOG_FIELD_REQUEST_ID: reqid,41LOG_FIELD_REQUEST: fmt.Sprintf("%s %s", r.Method, r.URL),42"request_content_length": strconv.FormatInt(r.ContentLength, 10),43}4445log.WithFields(logFields).Debug("handling request")46r = r.WithContext(context.WithValue(r.Context(), REQUEST_ID_CTX, reqid))4748upstream := o.GetUpstreamUrl(r)49r = r.WithContext(context.WithValue(r.Context(), UPSTREAM_CTX, upstream))5051if o.IsDisabledCache(upstream) {52log.WithFields(logFields).WithField("upstream", upstream.String()).Debug("go without cache")53p.ServeHTTP(rw, r)54o.finishLog(logFields, start, false, false)55o.metrics.DurationRequestProcessingHistogram.Observe(time.Since(start).Seconds())56return57}5859key, err := o.key(r)60if err != nil {61log.WithFields(logFields).WithError(err).Error("cannot create cache key")62p.ServeHTTP(rw, r)63o.finishLog(logFields, start, hitCacheRegular, hitCacheBackup)64o.metrics.DurationRequestProcessingHistogram.Observe(time.Since(start).Seconds())65return66}67r = r.WithContext(context.WithValue(r.Context(), REQUEST_CACHE_KEY_CTX, key))68logFields[LOG_FIELD_REQUEST] = key6970if o.Config.CacheDurationRegular > 0 {71cached, ok, err := o.ReadCache(key)72if err != nil {73log.WithFields(logFields).WithError(err).Error("cannot read from cache")74} else if !ok {75log.WithFields(logFields).Debug("cache has no entry for key")76} else {77hitCacheBackup = true78dateHeader := cached.Header.Get("Date")79log.WithFields(logFields).Debugf("there is a cached value with date: %s", dateHeader)80t, err := time.Parse("Mon, _2 Jan 2006 15:04:05 MST", dateHeader)81if err != nil {82log.WithFields(logFields).WithError(err).Warn("cannot parse date header of cached value")83} else {84minDate := time.Now().Add(-time.Duration(o.Config.CacheDurationRegular))85if t.After(minDate) {86hitCacheRegular = true87log.WithFields(logFields).Debugf("cached value is younger than %s - using cached value", o.Config.CacheDurationRegular)88for k, v := range cached.Header {89for i, val := range v {90if i == 0 {91rw.Header().Set(k, val)92} else {93rw.Header().Add(k, val)94}95}96}97if v := rw.Header().Get("Access-Control-Allow-Origin"); v != "" && v != "*" {98rw.Header().Set("Access-Control-Allow-Origin", r.Header.Get("Origin"))99}100rw.Header().Set("X-Cache", "HIT")101rw.WriteHeader(cached.StatusCode)102rw.Write(cached.Body)103o.finishLog(logFields, start, hitCacheRegular, hitCacheBackup)104o.metrics.DurationRequestProcessingHistogram.Observe(time.Since(start).Seconds())105return106} else {107log.WithFields(logFields).Debugf("cached value is older than %s - ignoring cached value", o.Config.CacheDurationRegular)108}109}110}111}112113duration := time.Since(start)114log.WithFields(logFields).WithFields(o.DurationLogFields(duration)).Debug("processing request finished")115o.metrics.DurationRequestProcessingHistogram.Observe(duration.Seconds())116117p.ServeHTTP(rw, r)118o.finishLog(logFields, start, hitCacheRegular, hitCacheBackup)119}120}121122func (o *OpenVSXProxy) finishLog(logFields logrus.Fields, start time.Time, hitCacheRegular, hitCacheBackup bool) {123duration := time.Since(start)124o.metrics.DurationOverallHistogram.Observe(duration.Seconds())125if hitCacheBackup {126o.metrics.BackupCacheHitCounter.Inc()127} else {128o.metrics.BackupCacheMissCounter.Inc()129}130if hitCacheRegular {131o.metrics.RegularCacheHitServeCounter.Inc()132} else {133o.metrics.RegularCacheMissCounter.Inc()134}135log.136WithFields(logFields).137WithFields(o.DurationLogFields(duration)).138WithField("hit_cache_regular", hitCacheRegular).139WithField("hit_cache_backup", hitCacheBackup).140Info("request finished")141}142143144