mirror of
				https://codeberg.org/forgejo/forgejo.git
				synced 2025-11-04 08:21:11 +00:00 
			
		
		
		
	* Use vendored go-swagger * vendor go-swagger * revert un wanteed change * remove un-needed GO111MODULE * Update Makefile Co-Authored-By: techknowlogick <matti@mdranta.net>
		
			
				
	
	
		
			174 lines
		
	
	
	
		
			4.8 KiB
		
	
	
	
		
			Go
		
	
	
	
		
			Vendored
		
	
	
	
			
		
		
	
	
			174 lines
		
	
	
	
		
			4.8 KiB
		
	
	
	
		
			Go
		
	
	
	
		
			Vendored
		
	
	
	
// Copyright 2013 The Gorilla Authors. All rights reserved.
 | 
						|
// Use of this source code is governed by a BSD-style
 | 
						|
// license that can be found in the LICENSE file.
 | 
						|
 | 
						|
package handlers
 | 
						|
 | 
						|
import (
 | 
						|
	"bufio"
 | 
						|
	"fmt"
 | 
						|
	"net"
 | 
						|
	"net/http"
 | 
						|
	"sort"
 | 
						|
	"strings"
 | 
						|
)
 | 
						|
 | 
						|
// MethodHandler is an http.Handler that dispatches to a handler whose key in the
 | 
						|
// MethodHandler's map matches the name of the HTTP request's method, eg: GET
 | 
						|
//
 | 
						|
// If the request's method is OPTIONS and OPTIONS is not a key in the map then
 | 
						|
// the handler responds with a status of 200 and sets the Allow header to a
 | 
						|
// comma-separated list of available methods.
 | 
						|
//
 | 
						|
// If the request's method doesn't match any of its keys the handler responds
 | 
						|
// with a status of HTTP 405 "Method Not Allowed" and sets the Allow header to a
 | 
						|
// comma-separated list of available methods.
 | 
						|
type MethodHandler map[string]http.Handler
 | 
						|
 | 
						|
func (h MethodHandler) ServeHTTP(w http.ResponseWriter, req *http.Request) {
 | 
						|
	if handler, ok := h[req.Method]; ok {
 | 
						|
		handler.ServeHTTP(w, req)
 | 
						|
	} else {
 | 
						|
		allow := []string{}
 | 
						|
		for k := range h {
 | 
						|
			allow = append(allow, k)
 | 
						|
		}
 | 
						|
		sort.Strings(allow)
 | 
						|
		w.Header().Set("Allow", strings.Join(allow, ", "))
 | 
						|
		if req.Method == "OPTIONS" {
 | 
						|
			w.WriteHeader(http.StatusOK)
 | 
						|
		} else {
 | 
						|
			http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
 | 
						|
		}
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
// responseLogger is wrapper of http.ResponseWriter that keeps track of its HTTP
 | 
						|
// status code and body size
 | 
						|
type responseLogger struct {
 | 
						|
	w      http.ResponseWriter
 | 
						|
	status int
 | 
						|
	size   int
 | 
						|
}
 | 
						|
 | 
						|
func (l *responseLogger) Header() http.Header {
 | 
						|
	return l.w.Header()
 | 
						|
}
 | 
						|
 | 
						|
func (l *responseLogger) Write(b []byte) (int, error) {
 | 
						|
	size, err := l.w.Write(b)
 | 
						|
	l.size += size
 | 
						|
	return size, err
 | 
						|
}
 | 
						|
 | 
						|
func (l *responseLogger) WriteHeader(s int) {
 | 
						|
	l.w.WriteHeader(s)
 | 
						|
	l.status = s
 | 
						|
}
 | 
						|
 | 
						|
func (l *responseLogger) Status() int {
 | 
						|
	return l.status
 | 
						|
}
 | 
						|
 | 
						|
func (l *responseLogger) Size() int {
 | 
						|
	return l.size
 | 
						|
}
 | 
						|
 | 
						|
func (l *responseLogger) Flush() {
 | 
						|
	f, ok := l.w.(http.Flusher)
 | 
						|
	if ok {
 | 
						|
		f.Flush()
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
type hijackLogger struct {
 | 
						|
	responseLogger
 | 
						|
}
 | 
						|
 | 
						|
func (l *hijackLogger) Hijack() (net.Conn, *bufio.ReadWriter, error) {
 | 
						|
	h := l.responseLogger.w.(http.Hijacker)
 | 
						|
	conn, rw, err := h.Hijack()
 | 
						|
	if err == nil && l.responseLogger.status == 0 {
 | 
						|
		// The status will be StatusSwitchingProtocols if there was no error and
 | 
						|
		// WriteHeader has not been called yet
 | 
						|
		l.responseLogger.status = http.StatusSwitchingProtocols
 | 
						|
	}
 | 
						|
	return conn, rw, err
 | 
						|
}
 | 
						|
 | 
						|
type closeNotifyWriter struct {
 | 
						|
	loggingResponseWriter
 | 
						|
	http.CloseNotifier
 | 
						|
}
 | 
						|
 | 
						|
type hijackCloseNotifier struct {
 | 
						|
	loggingResponseWriter
 | 
						|
	http.Hijacker
 | 
						|
	http.CloseNotifier
 | 
						|
}
 | 
						|
 | 
						|
// isContentType validates the Content-Type header matches the supplied
 | 
						|
// contentType. That is, its type and subtype match.
 | 
						|
func isContentType(h http.Header, contentType string) bool {
 | 
						|
	ct := h.Get("Content-Type")
 | 
						|
	if i := strings.IndexRune(ct, ';'); i != -1 {
 | 
						|
		ct = ct[0:i]
 | 
						|
	}
 | 
						|
	return ct == contentType
 | 
						|
}
 | 
						|
 | 
						|
// ContentTypeHandler wraps and returns a http.Handler, validating the request
 | 
						|
// content type is compatible with the contentTypes list. It writes a HTTP 415
 | 
						|
// error if that fails.
 | 
						|
//
 | 
						|
// Only PUT, POST, and PATCH requests are considered.
 | 
						|
func ContentTypeHandler(h http.Handler, contentTypes ...string) http.Handler {
 | 
						|
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
 | 
						|
		if !(r.Method == "PUT" || r.Method == "POST" || r.Method == "PATCH") {
 | 
						|
			h.ServeHTTP(w, r)
 | 
						|
			return
 | 
						|
		}
 | 
						|
 | 
						|
		for _, ct := range contentTypes {
 | 
						|
			if isContentType(r.Header, ct) {
 | 
						|
				h.ServeHTTP(w, r)
 | 
						|
				return
 | 
						|
			}
 | 
						|
		}
 | 
						|
		http.Error(w, fmt.Sprintf("Unsupported content type %q; expected one of %q", r.Header.Get("Content-Type"), contentTypes), http.StatusUnsupportedMediaType)
 | 
						|
	})
 | 
						|
}
 | 
						|
 | 
						|
const (
 | 
						|
	// HTTPMethodOverrideHeader is a commonly used
 | 
						|
	// http header to override a request method.
 | 
						|
	HTTPMethodOverrideHeader = "X-HTTP-Method-Override"
 | 
						|
	// HTTPMethodOverrideFormKey is a commonly used
 | 
						|
	// HTML form key to override a request method.
 | 
						|
	HTTPMethodOverrideFormKey = "_method"
 | 
						|
)
 | 
						|
 | 
						|
// HTTPMethodOverrideHandler wraps and returns a http.Handler which checks for
 | 
						|
// the X-HTTP-Method-Override header or the _method form key, and overrides (if
 | 
						|
// valid) request.Method with its value.
 | 
						|
//
 | 
						|
// This is especially useful for HTTP clients that don't support many http verbs.
 | 
						|
// It isn't secure to override e.g a GET to a POST, so only POST requests are
 | 
						|
// considered.  Likewise, the override method can only be a "write" method: PUT,
 | 
						|
// PATCH or DELETE.
 | 
						|
//
 | 
						|
// Form method takes precedence over header method.
 | 
						|
func HTTPMethodOverrideHandler(h http.Handler) http.Handler {
 | 
						|
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
 | 
						|
		if r.Method == "POST" {
 | 
						|
			om := r.FormValue(HTTPMethodOverrideFormKey)
 | 
						|
			if om == "" {
 | 
						|
				om = r.Header.Get(HTTPMethodOverrideHeader)
 | 
						|
			}
 | 
						|
			if om == "PUT" || om == "PATCH" || om == "DELETE" {
 | 
						|
				r.Method = om
 | 
						|
			}
 | 
						|
		}
 | 
						|
		h.ServeHTTP(w, r)
 | 
						|
	})
 | 
						|
}
 |