mirror of
				https://github.com/go-gitea/gitea.git
				synced 2025-11-04 06:24:11 +01:00 
			
		
		
		
	The "modules/context.go" is too large to maintain. This PR splits it to separate files, eg: context_request.go, context_response.go, context_serve.go This PR will help: 1. The future refactoring for Gitea's web context (eg: simplify the context) 2. Introduce proper "range request" support 3. Introduce context function This PR only moves code, doesn't change any logic.
		
			
				
	
	
		
			75 lines
		
	
	
		
			2.1 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			75 lines
		
	
	
		
			2.1 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
// Copyright 2023 The Gitea Authors. All rights reserved.
 | 
						|
// SPDX-License-Identifier: MIT
 | 
						|
 | 
						|
package context
 | 
						|
 | 
						|
import (
 | 
						|
	"fmt"
 | 
						|
	"io"
 | 
						|
	"net/http"
 | 
						|
	"net/url"
 | 
						|
	"strconv"
 | 
						|
	"strings"
 | 
						|
	"time"
 | 
						|
 | 
						|
	"code.gitea.io/gitea/modules/httpcache"
 | 
						|
	"code.gitea.io/gitea/modules/typesniffer"
 | 
						|
)
 | 
						|
 | 
						|
type ServeHeaderOptions struct {
 | 
						|
	ContentType        string // defaults to "application/octet-stream"
 | 
						|
	ContentTypeCharset string
 | 
						|
	ContentLength      *int64
 | 
						|
	Disposition        string // defaults to "attachment"
 | 
						|
	Filename           string
 | 
						|
	CacheDuration      time.Duration // defaults to 5 minutes
 | 
						|
	LastModified       time.Time
 | 
						|
}
 | 
						|
 | 
						|
// SetServeHeaders sets necessary content serve headers
 | 
						|
func (ctx *Context) SetServeHeaders(opts *ServeHeaderOptions) {
 | 
						|
	header := ctx.Resp.Header()
 | 
						|
 | 
						|
	contentType := typesniffer.ApplicationOctetStream
 | 
						|
	if opts.ContentType != "" {
 | 
						|
		if opts.ContentTypeCharset != "" {
 | 
						|
			contentType = opts.ContentType + "; charset=" + strings.ToLower(opts.ContentTypeCharset)
 | 
						|
		} else {
 | 
						|
			contentType = opts.ContentType
 | 
						|
		}
 | 
						|
	}
 | 
						|
	header.Set("Content-Type", contentType)
 | 
						|
	header.Set("X-Content-Type-Options", "nosniff")
 | 
						|
 | 
						|
	if opts.ContentLength != nil {
 | 
						|
		header.Set("Content-Length", strconv.FormatInt(*opts.ContentLength, 10))
 | 
						|
	}
 | 
						|
 | 
						|
	if opts.Filename != "" {
 | 
						|
		disposition := opts.Disposition
 | 
						|
		if disposition == "" {
 | 
						|
			disposition = "attachment"
 | 
						|
		}
 | 
						|
 | 
						|
		backslashEscapedName := strings.ReplaceAll(strings.ReplaceAll(opts.Filename, `\`, `\\`), `"`, `\"`) // \ -> \\, " -> \"
 | 
						|
		header.Set("Content-Disposition", fmt.Sprintf(`%s; filename="%s"; filename*=UTF-8''%s`, disposition, backslashEscapedName, url.PathEscape(opts.Filename)))
 | 
						|
		header.Set("Access-Control-Expose-Headers", "Content-Disposition")
 | 
						|
	}
 | 
						|
 | 
						|
	duration := opts.CacheDuration
 | 
						|
	if duration == 0 {
 | 
						|
		duration = 5 * time.Minute
 | 
						|
	}
 | 
						|
	httpcache.SetCacheControlInHeader(header, duration)
 | 
						|
 | 
						|
	if !opts.LastModified.IsZero() {
 | 
						|
		header.Set("Last-Modified", opts.LastModified.UTC().Format(http.TimeFormat))
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
// ServeContent serves content to http request
 | 
						|
func (ctx *Context) ServeContent(r io.ReadSeeker, opts *ServeHeaderOptions) {
 | 
						|
	ctx.SetServeHeaders(opts)
 | 
						|
	http.ServeContent(ctx.Resp, ctx.Req, opts.Filename, opts.LastModified, r)
 | 
						|
}
 |