1 Star 0 Fork 0

leonxiong/xtool

加入 Gitee
与超过 1400万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
文件
克隆/下载
httpserver.go 14.59 KB
一键复制 编辑 原始数据 按行查看 历史
leonxiong 提交于 2025-01-07 15:20 +08:00 . update simplehttp
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698
package simplehttp
import (
"bytes"
"fmt"
"gitee.com/xlm516/xtool/cast"
"gitee.com/xlm516/xtool/dbg"
"gitee.com/xlm516/xtool/sys"
xtime "gitee.com/xlm516/xtool/time"
"io"
"net"
"net/url"
"strings"
"sync"
"time"
)
type HttpRequest struct {
header url.Values
form url.Values
status HttpStatus
bodyBytes []byte
server *HttpServer
conn net.Conn
remoteIP string
}
func (me *HttpRequest) Form(name string) (string, bool) {
if me.form == nil {
return "", false
}
_, ok := me.form[name]
return me.form.Get(name), ok
}
func (me *HttpRequest) GetBody() []byte {
return me.bodyBytes
}
func (me *HttpRequest) GetHeaders() url.Values {
return me.header
}
func (me *HttpRequest) GetHeader(name string) string {
v, ok := me.header[name]
if ok == false {
v, ok = me.header[strings.ToLower(name)]
}
if ok && len(v) > 0 {
return v[0]
}
name = strings.ToLower(name)
for k, value := range me.header {
if name == strings.ToLower(k) {
v = value
ok = true
}
}
if ok && len(v) > 0 {
return v[0]
}
return ""
}
func (me *HttpRequest) GetStatus() HttpStatus {
return me.status
}
func (me *HttpRequest) RequestURI() string {
return me.status.URI
}
func (me *HttpRequest) Method() string {
return me.status.Method
}
func (me *HttpRequest) RemoteIP() string {
return me.remoteIP
}
func (me *HttpRequest) RemoteAddr() string {
if me.conn == nil {
return ""
}
return me.conn.RemoteAddr().String()
}
func (me *HttpRequest) LocalIP() string {
if me.conn == nil {
return ""
}
tmpIP := me.conn.LocalAddr().String()
index := strings.IndexByte(tmpIP, ':')
if index > 0 {
tmpIP = tmpIP[:index]
}
return tmpIP
}
func (me *HttpRequest) ParseForm() {
form, err := me.server.parseForm(me.status.URI, me.header, me.bodyBytes, true)
if err == nil {
me.form = form
} else {
me.form = make(map[string][]string)
}
}
type HttpResponse struct {
header map[string][]string
buf bytes.Buffer
code int
}
func (me *HttpResponse) SetStatusCode(code int) {
me.code = code
}
func (me *HttpResponse) WriteString(str string) {
me.buf.WriteString(str)
}
func (me *HttpResponse) Write(buf []byte) {
me.buf.Write(buf)
}
func (me *HttpResponse) SetHttpHeader(name string, value string) {
if me.header == nil {
me.header = make(map[string][]string)
}
me.header[name] = []string{value}
}
func (me *HttpResponse) DeleteHttpHeader(name string) {
if me.header == nil {
me.header = make(map[string][]string)
}
delete(me.header, name)
delete(me.header, strings.ToLower(name))
}
func (me *HttpResponse) ResetHttpHeader() {
me.header = make(map[string][]string)
}
func (me *HttpResponse) GetHeader(name string) string {
if me.header == nil {
me.header = make(map[string][]string)
}
v, ok := me.header[name]
if ok == false {
v, ok = me.header[strings.ToLower(name)]
}
if ok && len(v) > 0 {
return v[0]
}
return ""
}
type HttpInstance struct {
req *HttpRequest
resp *HttpResponse
}
func (me *HttpInstance) Form(name string) (string, bool) {
if me.req == nil {
return "", false
}
if me.req.form == nil {
return "", false
}
_, ok := me.req.form[name]
return me.req.form.Get(name), ok
}
func (me *HttpInstance) WriteString(str string) {
if me.resp == nil {
return
}
me.resp.WriteString(str)
}
func (me *HttpInstance) Write(data []byte) {
if me.resp == nil {
return
}
me.resp.Write(data)
}
func (me *HttpInstance) GetRequestData() []byte {
if me.req != nil {
return me.req.bodyBytes
}
return make([]byte, 0)
}
func (me *HttpInstance) GetStatus() HttpStatus {
return me.req.status
}
type Handler interface {
ServeHTTP(*HttpResponse, *HttpRequest)
}
type Router struct {
bindName string
name string
path string
rootDir string
handler interface{}
args []string
compileMutex sync.Mutex
fName string
fFile string
fLine int
userData interface{}
}
type RouterMgr struct {
absRouters map[string]*Router
routers []*Router
routerError *Router
enableCompiler bool
routerDebug bool
crossOrigin string //跨域
mutex sync.Mutex
}
func (me *RouterMgr) AddRouterFunc(path string, handler func(*HttpResponse, *HttpRequest), absPath bool, args ...string) *Router {
return me.AddRouter(path, handler, absPath, args...)
}
// AddRouter /*
/*
path: uri@name
uri: http uri
name: server name, optional
handler:
func(*HttpResponse, *HttpRequest)
func(*HttpInstance)
*/
func (me *RouterMgr) AddRouter(path string, handler interface{}, absPath bool, args ...string) *Router {
if path == "" {
return nil
}
me.mutex.Lock()
defer me.mutex.Unlock()
if absPath {
l := len(path)
if path[l-1] == '/' {
path = path[:l-1]
}
if path == "" {
path = "/"
}
}
router := new(Router)
router.handler = handler
if absPath {
}
if len(args) > 0 {
router.name = args[0]
tmpLen := len(path)
/* for http FileServer */
if args[0] == "fs" && tmpLen > 0 {
if path[tmpLen-1] != '/' {
path += "/"
}
rootDir := ""
if len(args) > 1 {
for i := 1; i < len(args); i++ {
router.args = append(router.args, args[i])
}
rootDir = sys.FormatDir(args[1])
}
if rootDir != "" {
}
}
}
router.path = path
if absPath {
me.absRouters[path] = router
} else {
existIndex := -1
for index, v := range me.routers {
if v.path == router.path && v.bindName == router.bindName {
existIndex = index
}
}
if existIndex > 0 {
*me.routers[existIndex] = *router
} else {
me.routers = append(me.routers, router)
}
}
return router
}
func (me *RouterMgr) GetRouter(path string) (*Router, string) {
if path == "" {
return me.routerError, ""
}
me.mutex.Lock()
defer me.mutex.Unlock()
secondUrl := ""
tmpUrl := path
router, ok := me.absRouters[tmpUrl]
if ok {
return router, ""
}
l := len(path)
if path != "/" && path[l-1] == '/' {
//path = path[:l-1]
//修改index为默认首页
path = path + "index"
router, ok := me.absRouters[path]
if ok {
return router, ""
}
}
tmpUrl = path
for i := 0; i < len(me.routers); i++ {
index := strings.Index(tmpUrl, me.routers[i].path)
//Dbg.Dbg("Get Router %s:%s, index=%d\n", tmpUrl, me.routers[i].path, index)
if index == 0 {
secondUrl = tmpUrl[len(me.routers[i].path):]
return me.routers[i], secondUrl
}
}
for i := 0; i < len(me.routers); i++ {
index := strings.Index(tmpUrl, me.routers[i].path)
//Dbg.Dbg("Get Router %s:%s, index=%d\n", tmpUrl, me.routers[i].path, index)
if index == 0 && (me.routers[i].bindName == "") {
secondUrl = tmpUrl[len(me.routers[i].path):]
return me.routers[i], secondUrl
}
}
return me.routerError, ""
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
type HttpServer struct {
bind string
bExit cast.Bool
debug cast.Bool
listen net.Listener
Router RouterMgr
OnConnect func(inst *HttpInstance, conn *net.TCPConn)
/* bAttach:true 不处理http请求,有调用处理连接 */
OnAccept func(conn net.Conn, bAttach *bool)
}
func NewHttpServer(bind string) *HttpServer {
resp := new(HttpServer)
resp.bind = bind
resp.init()
return resp
}
func (me *HttpServer) init() {
me.Router.absRouters = make(map[string]*Router)
me.Router.routers = make([]*Router, 0)
}
func (me *HttpServer) SetDebug(debug bool) {
me.debug.Set(debug)
}
func (me *HttpServer) AddBind(name string, bind string) {
me.bind = bind
}
func (me *HttpServer) Start() error {
listen, err := net.Listen("tcp", me.bind)
if err != nil {
return err
}
me.listen = listen
dbg.Dbg("http listen: %s\n", me.bind)
go me.loopListen()
return nil
}
func (me *HttpServer) Stop() {
me.bExit.Set(true)
if me.listen != nil {
me.listen.Close()
}
}
func (me *HttpServer) loopListen() {
me.bExit.Set(false)
for me.bExit.Get() == false {
conn, err := me.listen.Accept()
if err != nil {
dbg.Dbg("Error: %s\n", err.Error())
time.Sleep(time.Second * 2)
break
}
if me.debug.Get() {
dbg.Dbg("http accept %s\n", conn.RemoteAddr())
}
if me.OnAccept != nil {
bAttach := false
me.OnAccept(conn, &bAttach)
if bAttach {
continue
}
}
go me.doSession(conn)
}
}
func (me *HttpServer) GetRouter() *RouterMgr {
return &me.Router
}
func (me *HttpServer) getHttpStatus(code int) string {
switch code {
case 200:
return "OK"
default:
return "unknown"
}
}
func (me *HttpServer) build(code int, data []byte, resp *HttpResponse, keepAlive bool) []byte {
var buf bytes.Buffer
dataLen := 0
if data != nil {
dataLen = len(data)
}
if code <= 0 {
code = 200
}
buf.WriteString(fmt.Sprintf("HTTP/1.1 %d %s\r\n", code, me.getHttpStatus(code)))
buf.WriteString(fmt.Sprintf("Content-Length:%d\r\n", dataLen))
if resp != nil {
for k, v := range resp.header {
tmpName := strings.ToLower(k)
if tmpName == "content-length" {
continue
}
if v == nil || len(v) <= 0 {
continue
}
if tmpName == "connection" {
continue
}
buf.WriteString(fmt.Sprintf("%s:%s\r\n", k, v[0]))
}
_, haveDate := resp.header["Date"]
if haveDate == false {
buf.WriteString(fmt.Sprintf("Date: %s\r\n", xtime.Time2StrRFC1123(xtime.UnixTime())))
}
}
if !keepAlive {
buf.WriteString(fmt.Sprintf("Connection: close\r\n"))
} else {
//buf.WriteString(fmt.Sprintf("Connection: keep-alive\r\n"))
}
buf.WriteString("\r\n")
if data != nil {
buf.Write(data)
}
return buf.Bytes()
}
func (me *HttpServer) parseForm(uri string, header map[string][]string, data []byte, force bool) (url.Values, error) {
resp := make(map[string][]string)
queryArg := ""
index := strings.IndexByte(uri, '?')
if index > 0 {
queryArg = uri[index+1:]
}
v, err := url.ParseQuery(queryArg)
if err != nil {
dbg.Dbg("Error: %s by %s\n", err.Error(), queryArg)
return resp, err
}
resp = v
dataType, _ := header["content-type"]
if (dataType != nil && len(dataType) > 1 && strings.ToLower(dataType[0]) == "application/x-www-form-urlencoded") || force {
form, _ := url.ParseQuery(string(data))
if form != nil {
for k, v := range form {
resp[k] = v
}
}
}
return resp, nil
}
func Response(conn net.Conn, code int, codeCommand string, data []byte, contextType string) error {
var buf bytes.Buffer
dataLen := 0
if data != nil {
dataLen = len(data)
}
if code <= 0 {
code = 200
}
if codeCommand == "" {
codeCommand = "ok"
}
buf.WriteString(fmt.Sprintf("HTTP/1.1 %d %s\r\n", code, codeCommand))
buf.WriteString(fmt.Sprintf("Content-Length:%d\r\n", dataLen))
if contextType != "" {
buf.WriteString(fmt.Sprintf("Conent-Type:%s\r\n", contextType))
}
buf.WriteString("\r\n")
if data != nil {
buf.Write(data)
}
_, err := conn.Write(buf.Bytes())
return err
}
func (me *HttpServer) doSession(conn net.Conn) {
connTcp, ok := conn.(*net.TCPConn)
if ok != true {
dbg.Dbg("is not net tcp\n")
conn.Close()
return
}
closeConnect := true
defer func() {
if closeConnect {
if me.debug.Get() {
dbg.Dbg("http close: %s\n", conn.RemoteAddr())
}
conn.Close()
}
}()
var data bytes.Buffer
var header map[string][]string
var err error
var status HttpStatus
for {
header, err = receiveHttp(connTcp, &data, 900, 0, &status)
if err != nil {
if err != io.EOF {
dbg.Dbg("Error: %s\n", err.Error())
}
return
}
if header != nil {
if strings.ToLower(status.Method) == "connect" {
if me.OnConnect != nil {
closeConnect = false
response := new(HttpResponse)
request := new(HttpRequest)
request.status = status
request.header = header
request.conn = conn
request.remoteIP = conn.RemoteAddr().String()
index := strings.IndexByte(request.remoteIP, ':')
if index > 0 {
request.remoteIP = request.remoteIP[:index]
}
request.bodyBytes = data.Bytes()
response.header = make(map[string][]string)
response.code = 200
form, err := me.parseForm(status.URI, header, data.Bytes(), false)
if err == nil {
request.form = form
} else {
request.form = make(map[string][]string)
}
ins := new(HttpInstance)
ins.req = request
ins.resp = response
me.OnConnect(ins, connTcp)
}
return
}
}
path := status.URI
index := strings.IndexByte(path, '?')
if index > 0 {
path = path[:index]
}
router, _ := me.Router.GetRouter(path)
if router == nil {
b := me.build(404, []byte("Not find"), nil, true)
conn.Write(b)
return
}
response := new(HttpResponse)
request := new(HttpRequest)
request.status = status
request.header = header
request.bodyBytes = data.Bytes()
response.header = make(map[string][]string)
response.code = 200
form, err := me.parseForm(status.URI, header, data.Bytes(), false)
if err == nil {
request.form = form
} else {
request.form = make(map[string][]string)
}
switch gv := router.handler.(type) {
case func(*HttpResponse, *HttpRequest):
gv(response, request)
if response.code == -1 {
time.Sleep(time.Millisecond * 400)
conn.Close()
return
}
connType := response.GetHeader("Connection")
keepAlive := false
if request.GetHeader("Connection") == "keep-alive" {
keepAlive = true
}
if connType == "close" {
keepAlive = false
}
if response.code > 200 {
keepAlive = false
}
b := me.build(response.code, response.buf.Bytes(), response, keepAlive)
conn.Write(b)
if keepAlive == false {
if me.debug.Get() {
dbg.Dbg("not keepalive close: %s\n", connType)
}
return
}
case func(*HttpInstance):
ins := new(HttpInstance)
ins.req = request
ins.resp = response
gv(ins)
if response.code == -1 {
time.Sleep(time.Millisecond * 400)
conn.Close()
return
}
connType := response.GetHeader("Connection")
keepAlive := false
if request.GetHeader("Connection") == "keep-alive" {
keepAlive = true
}
if connType == "close" {
keepAlive = false
}
if response.code > 200 {
keepAlive = false
}
b := me.build(response.code, response.buf.Bytes(), response, keepAlive)
conn.Write(b)
if keepAlive == false {
if me.debug.Get() {
dbg.Dbg("not keepalive close\n")
}
return
}
}
}
}
func (me *HttpServer) RelayTCPConnect(conn net.Conn, remoteAddr string) error {
dbg.Dbg("handle connection to %s\n", remoteAddr)
var isClose cast.Bool
remoteConn, err := net.DialTimeout("tcp", remoteAddr, time.Second*10)
if err != nil {
dbg.Dbg("Error: %s\n", err.Error())
return err
}
go func() {
for isClose.Get() == false {
io.Copy(conn, remoteConn)
break
}
remoteConn.Close()
conn.Close()
}()
for isClose.Get() == false {
_, err := io.Copy(remoteConn, conn)
if err != nil {
dbg.Dbg("Connection Close\n")
}
isClose.Set(true)
break
}
conn.Close()
remoteConn.Close()
dbg.Dbg("close connection to %s\n", remoteAddr)
return nil
}
Loading...
马建仓 AI 助手
尝试更多
代码解读
代码找茬
代码优化
Go
1
https://gitee.com/xlm516/xtool.git
git@gitee.com:xlm516/xtool.git
xlm516
xtool
xtool
7db4253cb67d

搜索帮助