podman

Форк
0
150 строк · 4.4 Кб
1
// Copyright 2013 The Gorilla Authors. All rights reserved.
2
// Use of this source code is governed by a BSD-style
3
// license that can be found in the LICENSE file.
4

5
package handlers
6

7
import (
8
	"bufio"
9
	"fmt"
10
	"net"
11
	"net/http"
12
	"sort"
13
	"strings"
14
)
15

16
// MethodHandler is an http.Handler that dispatches to a handler whose key in the
17
// MethodHandler's map matches the name of the HTTP request's method, eg: GET
18
//
19
// If the request's method is OPTIONS and OPTIONS is not a key in the map then
20
// the handler responds with a status of 200 and sets the Allow header to a
21
// comma-separated list of available methods.
22
//
23
// If the request's method doesn't match any of its keys the handler responds
24
// with a status of HTTP 405 "Method Not Allowed" and sets the Allow header to a
25
// comma-separated list of available methods.
26
type MethodHandler map[string]http.Handler
27

28
func (h MethodHandler) ServeHTTP(w http.ResponseWriter, req *http.Request) {
29
	if handler, ok := h[req.Method]; ok {
30
		handler.ServeHTTP(w, req)
31
	} else {
32
		allow := []string{}
33
		for k := range h {
34
			allow = append(allow, k)
35
		}
36
		sort.Strings(allow)
37
		w.Header().Set("Allow", strings.Join(allow, ", "))
38
		if req.Method == http.MethodOptions {
39
			w.WriteHeader(http.StatusOK)
40
		} else {
41
			http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
42
		}
43
	}
44
}
45

46
// responseLogger is wrapper of http.ResponseWriter that keeps track of its HTTP
47
// status code and body size.
48
type responseLogger struct {
49
	w      http.ResponseWriter
50
	status int
51
	size   int
52
}
53

54
func (l *responseLogger) Write(b []byte) (int, error) {
55
	size, err := l.w.Write(b)
56
	l.size += size
57
	return size, err
58
}
59

60
func (l *responseLogger) WriteHeader(s int) {
61
	l.w.WriteHeader(s)
62
	l.status = s
63
}
64

65
func (l *responseLogger) Status() int {
66
	return l.status
67
}
68

69
func (l *responseLogger) Size() int {
70
	return l.size
71
}
72

73
func (l *responseLogger) Hijack() (net.Conn, *bufio.ReadWriter, error) {
74
	conn, rw, err := l.w.(http.Hijacker).Hijack()
75
	if err == nil && l.status == 0 {
76
		// The status will be StatusSwitchingProtocols if there was no error and
77
		// WriteHeader has not been called yet
78
		l.status = http.StatusSwitchingProtocols
79
	}
80
	return conn, rw, err
81
}
82

83
// isContentType validates the Content-Type header matches the supplied
84
// contentType. That is, its type and subtype match.
85
func isContentType(h http.Header, contentType string) bool {
86
	ct := h.Get("Content-Type")
87
	if i := strings.IndexRune(ct, ';'); i != -1 {
88
		ct = ct[0:i]
89
	}
90
	return ct == contentType
91
}
92

93
// ContentTypeHandler wraps and returns a http.Handler, validating the request
94
// content type is compatible with the contentTypes list. It writes a HTTP 415
95
// error if that fails.
96
//
97
// Only PUT, POST, and PATCH requests are considered.
98
func ContentTypeHandler(h http.Handler, contentTypes ...string) http.Handler {
99
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
100
		if !(r.Method == http.MethodPut || r.Method == http.MethodPost || r.Method == http.MethodPatch) {
101
			h.ServeHTTP(w, r)
102
			return
103
		}
104

105
		for _, ct := range contentTypes {
106
			if isContentType(r.Header, ct) {
107
				h.ServeHTTP(w, r)
108
				return
109
			}
110
		}
111
		http.Error(w, fmt.Sprintf("Unsupported content type %q; expected one of %q",
112
			r.Header.Get("Content-Type"),
113
			contentTypes),
114
			http.StatusUnsupportedMediaType)
115
	})
116
}
117

118
const (
119
	// HTTPMethodOverrideHeader is a commonly used
120
	// http header to override a request method.
121
	HTTPMethodOverrideHeader = "X-HTTP-Method-Override"
122
	// HTTPMethodOverrideFormKey is a commonly used
123
	// HTML form key to override a request method.
124
	HTTPMethodOverrideFormKey = "_method"
125
)
126

127
// HTTPMethodOverrideHandler wraps and returns a http.Handler which checks for
128
// the X-HTTP-Method-Override header or the _method form key, and overrides (if
129
// valid) request.Method with its value.
130
//
131
// This is especially useful for HTTP clients that don't support many http verbs.
132
// It isn't secure to override e.g a GET to a POST, so only POST requests are
133
// considered.  Likewise, the override method can only be a "write" method: PUT,
134
// PATCH or DELETE.
135
//
136
// Form method takes precedence over header method.
137
func HTTPMethodOverrideHandler(h http.Handler) http.Handler {
138
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
139
		if r.Method == http.MethodPost {
140
			om := r.FormValue(HTTPMethodOverrideFormKey)
141
			if om == "" {
142
				om = r.Header.Get(HTTPMethodOverrideHeader)
143
			}
144
			if om == http.MethodPut || om == http.MethodPatch || om == http.MethodDelete {
145
				r.Method = om
146
			}
147
		}
148
		h.ServeHTTP(w, r)
149
	})
150
}
151

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.