forked from coffeehc/httpx
/
server.go
160 lines (142 loc) · 4.4 KB
/
server.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
// server
package web
import (
"crypto/tls"
"errors"
"net"
"net/http"
"strconv"
"strings"
"time"
"github.com/bradfitz/http2"
"github.com/coffeehc/logger"
)
const (
GET = "GET"
POST = "POST"
PUT = "PUT"
DELETE = "DELETE"
HEAD = "HEAD"
TRACE = "TRACE"
CONNECT = "CONNECT"
)
type RequestHandler func(request *http.Request, pathFragments map[string]string, reply *Reply)
type defauleAction struct {
path string
method string
service RequestHandler
}
func (this *defauleAction) GetPath() string {
return this.path
}
func (this *defauleAction) GetMethod() string {
return this.method
}
func (this *defauleAction) Service(request *http.Request, pathFragments map[string]string, reply *Reply) {
this.service(request, pathFragments, reply)
}
type ServerConfig struct {
Addr string
Port int
ReadTimeout time.Duration // 读的最大Timeout时间
WriteTimeout time.Duration // 写的最大Timeout时间
MaxHeaderBytes int // 请求头的最大长度
TLSConfig *tls.Config // 配置TLS
serverAddr string
OpenHttp2 bool //是否开启http2
}
type Server struct {
router *routingDispatcher
listener net.Listener
config *ServerConfig
}
//创建一个Server,参数可以为空,默认使用0.0.0.0:8888
func NewServer(serverConfig *ServerConfig) *Server {
if serverConfig == nil {
serverConfig = &ServerConfig{Addr: "0.0.0.0"}
}
if serverConfig.Port == 0 {
serverConfig.Port = 8888
}
if serverConfig.OpenHttp2 && serverConfig.TLSConfig == nil {
logger.Error("open http2 need TLS support")
return nil
}
addr := net.JoinHostPort(serverConfig.Addr, strconv.Itoa(serverConfig.Port))
serverAddr, err := net.ResolveTCPAddr("tcp", addr)
if err != nil {
logger.Error("can't parse the server addr [%s],cause:%s", addr, err)
return nil
}
serverConfig.serverAddr = serverAddr.String()
return &Server{router: newRoutingDispatcher(), config: serverConfig}
}
func (this *Server) Start() error {
logger.Debug("serverConfig is %#v", this.config)
this.router.matcher.sort()
conf := this.config
server := &http.Server{Handler: http.HandlerFunc(this.serverHttpHandler), MaxHeaderBytes: conf.MaxHeaderBytes, TLSConfig: conf.TLSConfig}
if conf.ReadTimeout > 0 {
server.ReadTimeout = conf.ReadTimeout
}
if conf.WriteTimeout > 0 {
server.WriteTimeout = conf.WriteTimeout
}
http2.ConfigureServer(server, &http2.Server{})
var err error
this.listener, err = net.Listen("tcp", conf.serverAddr)
if err != nil {
return errors.New(logger.Error("listen [%s] fail:%s", conf.serverAddr, err))
}
logger.Info("start HttpServer :%s", conf.serverAddr)
keepAliveListrener := tcpKeepAliveListener{this.listener.(*net.TCPListener)}
if conf.TLSConfig != nil {
conf.TLSConfig.NextProtos = append(conf.TLSConfig.NextProtos, "http/1.1")
go server.Serve(tls.NewListener(keepAliveListrener, conf.TLSConfig))
} else {
go server.Serve(keepAliveListrener)
}
return nil
}
type tcpKeepAliveListener struct {
*net.TCPListener
}
func (ln tcpKeepAliveListener) Accept() (c net.Conn, err error) {
tc, err := ln.AcceptTCP()
if err != nil {
return
}
tc.SetKeepAlive(true)
tc.SetKeepAlivePeriod(time.Minute)
return tc, nil
}
func (this *Server) serverHttpHandler(responseWriter http.ResponseWriter, request *http.Request) {
request.URL.Path = strings.Replace(request.URL.Path, "//", "/", -1)
reply := newReply(responseWriter)
this.router.filters[0].filter(request, reply)
//TODO 处理异常的StatusCode
if !reply.openStream {
responseWriter.Header().Set("Connection", "close")
reply.write()
}
request.Body.Close()
}
func (this *Server) Stop() {
if this.listener != nil {
logger.Debug("Close Http Server")
this.listener.Close()
}
}
func (server *Server) Regedit(path string, method string, service RequestHandler) error {
return server.router.matcher.regeditAction(&defauleAction{path, method, service})
}
func (server *Server) RegeditWebSocket(path string, service WebScoketHandler) error {
adapter := &webScoketAdapter{service}
return server.router.matcher.regeditAction(&defauleAction{path, GET, adapter.webScoketHandlerAdapter})
}
func (server *Server) AddFilter(uriPattern string, actionFilter ActionFilter) {
server.router.addFilter(newServletStyleUriPatternMatcher(uriPattern), actionFilter)
}
func (server *Server) AddFilterWithRegex(uriPattern string, actionFilter ActionFilter) {
server.router.addFilter(newRegexUriPatternMatcher(uriPattern), actionFilter)
}