Upload files to "/"
This commit is contained in:
		
						commit
						e1e41070af
					
				
							
								
								
									
										172
									
								
								gitea.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										172
									
								
								gitea.go
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,172 @@ | |||||||
|  | package gitea | ||||||
|  | 
 | ||||||
|  | import ( | ||||||
|  | 	"fmt" | ||||||
|  | 	"io" | ||||||
|  | 	"net/http" | ||||||
|  | 	"strings" | ||||||
|  | 
 | ||||||
|  | 	"github.com/caddyserver/caddy/v2" | ||||||
|  | 	"github.com/caddyserver/caddy/v2/caddyconfig/caddyfile" | ||||||
|  | 	"github.com/caddyserver/caddy/v2/caddyconfig/httpcaddyfile" | ||||||
|  | 	"github.com/caddyserver/caddy/v2/modules/caddyhttp" | ||||||
|  | 	"git.supported.systems/rsp2k/caddy-gitea" | ||||||
|  | ) | ||||||
|  | 
 | ||||||
|  | func init() { | ||||||
|  | 	// Register the module and the Caddyfile handler directive. | ||||||
|  | 	caddy.RegisterModule(Middleware{}) | ||||||
|  | 	httpcaddyfile.RegisterHandlerDirective("gitea", parseCaddyfile) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // parseCaddyfile creates and configures the module from Caddyfile input. | ||||||
|  | func parseCaddyfile(h httpcaddyfile.Helper) (caddyhttp.MiddlewareHandler, error) { | ||||||
|  | 	var m Middleware | ||||||
|  | 	if err := m.UnmarshalCaddyfile(h.Dispenser); err != nil { | ||||||
|  | 		return nil, err | ||||||
|  | 	} | ||||||
|  | 	return &m, nil | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // Middleware implements the Gitea plugin. | ||||||
|  | type Middleware struct { | ||||||
|  | 	// The Gitea client is created during Provision. | ||||||
|  | 	Client *gitea.Client `json:"-"` | ||||||
|  | 
 | ||||||
|  | 	// Required/optional configuration fields: | ||||||
|  | 	Server             string `json:"server,omitempty"`              // e.g. "https://gitea.example.com" | ||||||
|  | 	Token              string `json:"token,omitempty"`               // API token if needed | ||||||
|  | 	GiteaPages         string `json:"gitea_pages,omitempty"`         // e.g. URL for Gitea pages | ||||||
|  | 	GiteaPagesAllowAll string `json:"gitea_pages_allowall,omitempty"`  // configuration for allow-all pages mode | ||||||
|  | 	Domain             string `json:"domain,omitempty"`              // if set, used to split subdomain parts | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // CaddyModule returns the Caddy module information. | ||||||
|  | func (Middleware) CaddyModule() caddy.ModuleInfo { | ||||||
|  | 	return caddy.ModuleInfo{ | ||||||
|  | 		ID: "http.handlers.gitea", | ||||||
|  | 		New: func() caddy.Module { | ||||||
|  | 			return new(Middleware) | ||||||
|  | 		}, | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // Provision creates the Gitea client. | ||||||
|  | func (m *Middleware) Provision(ctx caddy.Context) error { | ||||||
|  | 	// Validate required configuration. | ||||||
|  | 	if m.Server == "" { | ||||||
|  | 		return fmt.Errorf("gitea: server must be specified") | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	var err error | ||||||
|  | 	m.Client, err = gitea.NewClient(m.Server, m.Token, m.GiteaPages, m.GiteaPagesAllowAll) | ||||||
|  | 	return err | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // Validate performs additional configuration validation. | ||||||
|  | func (m *Middleware) Validate() error { | ||||||
|  | 	if m.Server == "" { | ||||||
|  | 		return fmt.Errorf("gitea: server is required") | ||||||
|  | 	} | ||||||
|  | 	return nil | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // UnmarshalCaddyfile sets up the configuration from Caddyfile tokens. | ||||||
|  | func (m *Middleware) UnmarshalCaddyfile(d *caddyfile.Dispenser) error { | ||||||
|  | 	// Each block of tokens (if more than one block is given) will be processed. | ||||||
|  | 	for d.Next() { | ||||||
|  | 		// Process all subdirectives in the block. | ||||||
|  | 		for n := d.Nesting(); d.NextBlock(n); { | ||||||
|  | 			switch d.Val() { | ||||||
|  | 			case "server": | ||||||
|  | 				if !d.NextArg() { | ||||||
|  | 					return d.ArgErr() | ||||||
|  | 				} | ||||||
|  | 				m.Server = d.Val() | ||||||
|  | 			case "token": | ||||||
|  | 				if !d.NextArg() { | ||||||
|  | 					return d.ArgErr() | ||||||
|  | 				} | ||||||
|  | 				m.Token = d.Val() | ||||||
|  | 			case "gitea_pages": | ||||||
|  | 				if !d.NextArg() { | ||||||
|  | 					return d.ArgErr() | ||||||
|  | 				} | ||||||
|  | 				m.GiteaPages = d.Val() | ||||||
|  | 			case "gitea_pages_allowall": | ||||||
|  | 				if !d.NextArg() { | ||||||
|  | 					return d.ArgErr() | ||||||
|  | 				} | ||||||
|  | 				m.GiteaPagesAllowAll = d.Val() | ||||||
|  | 			case "domain": | ||||||
|  | 				if !d.NextArg() { | ||||||
|  | 					return d.ArgErr() | ||||||
|  | 				} | ||||||
|  | 				m.Domain = d.Val() | ||||||
|  | 			default: | ||||||
|  | 				return d.Errf("gitea: unrecognized subdirective '%s'", d.Val()) | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 	return nil | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // ServeHTTP implements the HTTP handler. It uses the Gitea client to | ||||||
|  | // retrieve content based on the request’s host and path. | ||||||
|  | func (m Middleware) ServeHTTP(w http.ResponseWriter, r *http.Request, next caddyhttp.Handler) error { | ||||||
|  | 	// Derive the file path from the request's host and URL. | ||||||
|  | 	// | ||||||
|  | 	// If m.Domain is set then we expect requests in one of two forms: | ||||||
|  | 	//   - repo.username.<domain>  (len=2 after splitting by '.') | ||||||
|  | 	//   - branch.repo.username.<domain>  (len=3) | ||||||
|  | 	// | ||||||
|  | 	// Otherwise, we just use the first segment of the host. | ||||||
|  | 	host := r.Host | ||||||
|  | 	if m.Domain != "" { | ||||||
|  | 		// Remove the configured domain (and a trailing dot, if any) | ||||||
|  | 		host = strings.TrimSuffix(host, m.Domain) | ||||||
|  | 		host = strings.TrimRight(host, ".") | ||||||
|  | 	} | ||||||
|  | 	parts := strings.Split(host, ".") | ||||||
|  | 	var fp string | ||||||
|  | 	// Default: use first part plus the URL path. | ||||||
|  | 	if len(parts) > 0 { | ||||||
|  | 		fp = parts[0] + r.URL.Path | ||||||
|  | 	} | ||||||
|  | 	// Adjust based on subdomain count when a domain is configured. | ||||||
|  | 	ref := r.URL.Query().Get("ref") | ||||||
|  | 	if m.Domain != "" { | ||||||
|  | 		switch len(parts) { | ||||||
|  | 		case 2: | ||||||
|  | 			// Format: repo.username.<domain> | ||||||
|  | 			fp = parts[1] + "/" + parts[0] + r.URL.Path | ||||||
|  | 		case 3: | ||||||
|  | 			// Format: branch.repo.username.<domain> | ||||||
|  | 			fp = parts[2] + "/" + parts[1] + r.URL.Path | ||||||
|  | 			ref = parts[0] | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	// Open the file from Gitea. | ||||||
|  | 	f, err := m.Client.Open(fp, ref) | ||||||
|  | 	if err != nil { | ||||||
|  | 		// Return a 404 error if the file isn’t found. | ||||||
|  | 		return caddyhttp.Error(http.StatusNotFound, err) | ||||||
|  | 	} | ||||||
|  | 	// If the returned file supports closing, ensure it gets closed. | ||||||
|  | 	if closer, ok := f.(io.Closer); ok { | ||||||
|  | 		defer closer.Close() | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	// Copy the file's contents to the response. | ||||||
|  | 	_, err = io.Copy(w, f) | ||||||
|  | 	return err | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // Interface guards | ||||||
|  | var ( | ||||||
|  | 	_ caddy.Provisioner           = (*Middleware)(nil) | ||||||
|  | 	_ caddy.Validator             = (*Middleware)(nil) | ||||||
|  | 	_ caddyhttp.MiddlewareHandler = (*Middleware)(nil) | ||||||
|  | 	_ caddyfile.Unmarshaler       = (*Middleware)(nil) | ||||||
|  | ) | ||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user