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