MCPcopy Index your code
hub / github.com/rilldata/rill / assetHandler

Method assetHandler

admin/server/assets.go:171–249  ·  view source on GitHub ↗

assetHandler serves a previously uploaded file asset. If the asset is marked as public, it sets caching headers that allows CDNs and browsers to cache the asset. If the asset is not marked as public, it guarantees that the asset can only be accessed by authenticated users with read access to the ass

(w http.ResponseWriter, r *http.Request)

Source from the content-addressed store, hash-verified

169// If the asset is marked as public, it sets caching headers that allows CDNs and browsers to cache the asset.
170// If the asset is not marked as public, it guarantees that the asset can only be accessed by authenticated users with read access to the asset's organization.
171func (s *Server) assetHandler(w http.ResponseWriter, r *http.Request) error {
172 // Params
173 assetID := r.PathValue("asset_id")
174
175 // Find the asset
176 asset, err := s.admin.DB.FindAsset(r.Context(), assetID)
177 if err != nil {
178 return httputil.Error(http.StatusNotFound, err)
179 }
180 if asset.OrganizationID == nil {
181 return httputil.Errorf(http.StatusNotFound, "the requested asset has been soft deleted")
182 }
183
184 // Check permissions
185 claims := auth.GetClaims(r.Context())
186 if !asset.Public && !claims.OrganizationPermissions(r.Context(), *asset.OrganizationID).ReadOrg {
187 ok, err := s.admin.DB.CheckOrganizationHasPublicProjects(r.Context(), *asset.OrganizationID)
188 if err != nil {
189 return err
190 }
191 if !ok {
192 return httputil.Errorf(http.StatusForbidden, "does not have permission to access the asset")
193 }
194 }
195
196 // Parse the asset's path, which has the form "gs://<bucket>/<path>"
197 u, err := url.Parse(asset.Path)
198 if err != nil {
199 return err
200 }
201
202 // Set caching headers if the asset is public
203 if asset.Public {
204 w.Header().Set("Cache-Control", "public, max-age=31536000")
205 } else {
206 w.Header().Set("Cache-Control", "no-store")
207 }
208
209 // Set the content type header
210 found := false
211 for _, t := range supportedAssetTypes {
212 if strings.HasSuffix(u.Path, t.Extension) { // Using HasSuffix to correctly check multi-part extensions like .tar.gz
213 w.Header().Set("Content-Type", t.MIMEType)
214 found = true
215 break
216 }
217 }
218 if !found { // Fallback content type
219 w.Header().Set("Content-Type", "application/octet-stream")
220 }
221
222 // Set the content disposition header
223 // Using "attachment" as a security measure to prevent browsers from rendering the asset, which is a security vulnerability for e.g. SVGs containing scripts.
224 w.Header().Set("Content-Disposition", fmt.Sprintf("attachment; filename=%s", path.Base(u.Path)))
225
226 // Set the status code
227 w.WriteHeader(http.StatusOK)
228

Callers

nothing calls this directly

Calls 12

ErrorFunction · 0.92
ErrorfFunction · 0.92
GetClaimsFunction · 0.92
ParseMethod · 0.80
WriteHeaderMethod · 0.80
FindAssetMethod · 0.65
ContextMethod · 0.65
ErrMethod · 0.65
CloseMethod · 0.65
SetMethod · 0.45

Tested by

no test coverage detected