http.go 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271
  1. package proxy
  2. import (
  3. "bufio"
  4. "crypto/tls"
  5. "github.com/cnlh/nps/bridge"
  6. "github.com/cnlh/nps/lib/cache"
  7. "github.com/cnlh/nps/lib/common"
  8. "github.com/cnlh/nps/lib/conn"
  9. "github.com/cnlh/nps/lib/file"
  10. "github.com/cnlh/nps/server/connection"
  11. "github.com/cnlh/nps/vender/github.com/astaxie/beego/logs"
  12. "io"
  13. "net"
  14. "net/http"
  15. "net/http/httputil"
  16. "os"
  17. "path/filepath"
  18. "strconv"
  19. "strings"
  20. "sync"
  21. )
  22. type httpServer struct {
  23. BaseServer
  24. httpPort int
  25. httpsPort int
  26. httpServer *http.Server
  27. httpsServer *http.Server
  28. httpsListener net.Listener
  29. useCache bool
  30. cache *cache.Cache
  31. cacheLen int
  32. }
  33. func NewHttp(bridge *bridge.Bridge, c *file.Tunnel, httpPort, httpsPort int, useCache bool, cacheLen int) *httpServer {
  34. httpServer := &httpServer{
  35. BaseServer: BaseServer{
  36. task: c,
  37. bridge: bridge,
  38. Mutex: sync.Mutex{},
  39. },
  40. httpPort: httpPort,
  41. httpsPort: httpsPort,
  42. useCache: useCache,
  43. cacheLen: cacheLen,
  44. }
  45. if useCache {
  46. httpServer.cache = cache.New(cacheLen)
  47. }
  48. return httpServer
  49. }
  50. func (s *httpServer) Start() error {
  51. var err error
  52. if s.errorContent, err = common.ReadAllFromFile(filepath.Join(common.GetRunPath(), "web", "static", "page", "error.html")); err != nil {
  53. s.errorContent = []byte("easyProxy 404")
  54. }
  55. if s.httpPort > 0 {
  56. s.httpServer = s.NewServer(s.httpPort, "http")
  57. go func() {
  58. l, err := connection.GetHttpListener()
  59. if err != nil {
  60. logs.Error(err)
  61. os.Exit(0)
  62. }
  63. err = s.httpServer.Serve(l)
  64. if err != nil {
  65. logs.Error(err)
  66. os.Exit(0)
  67. }
  68. }()
  69. }
  70. if s.httpsPort > 0 {
  71. s.httpsServer = s.NewServer(s.httpsPort, "https")
  72. go func() {
  73. s.httpsListener, err = connection.GetHttpsListener()
  74. if err != nil {
  75. logs.Error(err)
  76. os.Exit(0)
  77. }
  78. logs.Error(NewHttpsServer(s.httpsListener, s.bridge, s.useCache, s.cacheLen).Start())
  79. }()
  80. }
  81. return nil
  82. }
  83. func (s *httpServer) Close() error {
  84. if s.httpsListener != nil {
  85. s.httpsListener.Close()
  86. }
  87. if s.httpsServer != nil {
  88. s.httpsServer.Close()
  89. }
  90. if s.httpServer != nil {
  91. s.httpServer.Close()
  92. }
  93. return nil
  94. }
  95. func (s *httpServer) handleTunneling(w http.ResponseWriter, r *http.Request) {
  96. hijacker, ok := w.(http.Hijacker)
  97. if !ok {
  98. http.Error(w, "Hijacking not supported", http.StatusInternalServerError)
  99. return
  100. }
  101. c, _, err := hijacker.Hijack()
  102. if err != nil {
  103. http.Error(w, err.Error(), http.StatusServiceUnavailable)
  104. }
  105. s.httpHandle(conn.NewConn(c), r)
  106. }
  107. func (s *httpServer) httpHandle(c *conn.Conn, r *http.Request) {
  108. var (
  109. isConn = false
  110. host *file.Host
  111. target net.Conn
  112. lastHost *file.Host
  113. err error
  114. connClient io.ReadWriteCloser
  115. scheme = r.URL.Scheme
  116. lk *conn.Link
  117. targetAddr string
  118. readReq bool
  119. reqCh = make(chan *http.Request)
  120. )
  121. if host, err = file.GetDb().GetInfoByHost(r.Host, r); err != nil {
  122. logs.Notice("the url %s %s %s can't be parsed!", r.URL.Scheme, r.Host, r.RequestURI)
  123. goto end
  124. }
  125. if err := s.CheckFlowAndConnNum(host.Client); err != nil {
  126. logs.Warn("client id %d, host id %d, error %s, when https connection", host.Client.Id, host.Id, err.Error())
  127. c.Close()
  128. return
  129. }
  130. defer host.Client.AddConn()
  131. lastHost = host
  132. for {
  133. start:
  134. if isConn {
  135. if err = s.auth(r, c, host.Client.Cnf.U, host.Client.Cnf.P); err != nil {
  136. logs.Warn("auth error", err, r.RemoteAddr)
  137. break
  138. }
  139. if targetAddr, err = host.Target.GetRandomTarget(); err != nil {
  140. logs.Warn(err.Error())
  141. break
  142. }
  143. lk = conn.NewLink(common.CONN_TCP, targetAddr, host.Client.Cnf.Crypt, host.Client.Cnf.Compress, r.RemoteAddr, host.Target.LocalProxy)
  144. if target, err = s.bridge.SendLinkInfo(host.Client.Id, lk, nil); err != nil {
  145. logs.Notice("connect to target %s error %s", lk.Host, err)
  146. break
  147. }
  148. connClient = conn.GetConn(target, lk.Crypt, lk.Compress, host.Client.Rate, true)
  149. isConn = false
  150. go func() {
  151. defer connClient.Close()
  152. defer c.Close()
  153. for {
  154. r := <-reqCh
  155. if resp, err := http.ReadResponse(bufio.NewReader(connClient), r); err != nil {
  156. return
  157. } else {
  158. //if the cache is start and the response is in the extension,store the response to the cache list
  159. if s.useCache && strings.Contains(r.URL.Path, ".") {
  160. b, err := httputil.DumpResponse(resp, true)
  161. if err != nil {
  162. return
  163. }
  164. c.Write(b)
  165. host.Flow.Add(0, int64(len(b)))
  166. s.cache.Add(filepath.Join(host.Host, r.URL.Path), b)
  167. } else {
  168. b, err := httputil.DumpResponse(resp, false)
  169. if err != nil {
  170. return
  171. }
  172. c.Write(b)
  173. if bodyLen, err := common.CopyBuffer(c, resp.Body); err != nil {
  174. return
  175. } else {
  176. host.Flow.Add(0, int64(len(b))+bodyLen)
  177. }
  178. }
  179. }
  180. }
  181. }()
  182. } else if readReq {
  183. r, err = http.ReadRequest(bufio.NewReader(c))
  184. if err != nil {
  185. break
  186. }
  187. r.URL.Scheme = scheme
  188. //What happened ,Why one character less???
  189. if r.Method == "ET" {
  190. r.Method = "GET"
  191. }
  192. if r.Method == "OST" {
  193. r.Method = "POST"
  194. }
  195. if hostTmp, err := file.GetDb().GetInfoByHost(r.Host, r); err != nil {
  196. logs.Notice("the url %s %s %s can't be parsed!", r.URL.Scheme, r.Host, r.RequestURI)
  197. break
  198. } else if host != lastHost {
  199. host = hostTmp
  200. lastHost = host
  201. isConn = true
  202. goto start
  203. }
  204. }
  205. //if the cache start and the request is in the cache list, return the cache
  206. if s.useCache {
  207. if v, ok := s.cache.Get(filepath.Join(host.Host, r.URL.Path)); ok {
  208. n, err := c.Write(v.([]byte))
  209. if err != nil {
  210. break
  211. }
  212. logs.Trace("%s request, method %s, host %s, url %s, remote address %s, return cache", r.URL.Scheme, r.Method, r.Host, r.URL.Path, c.RemoteAddr().String())
  213. host.Flow.Add(0, int64(n))
  214. //if return cache and does not create a new conn with client and Connection is not set or close, close the connection.
  215. if connClient == nil && (strings.ToLower(r.Header.Get("Connection")) == "close" || strings.ToLower(r.Header.Get("Connection")) == "") {
  216. c.Close()
  217. break
  218. }
  219. readReq = true
  220. goto start
  221. }
  222. }
  223. if connClient == nil {
  224. isConn = true
  225. goto start
  226. }
  227. readReq = true
  228. //change the host and header and set proxy setting
  229. common.ChangeHostAndHeader(r, host.HostChange, host.HeaderChange, c.Conn.RemoteAddr().String())
  230. b, err := httputil.DumpRequest(r, false)
  231. if err != nil {
  232. break
  233. }
  234. logs.Trace("%s request, method %s, host %s, url %s, remote address %s, target %s", r.URL.Scheme, r.Method, r.Host, r.URL.Path, c.RemoteAddr().String(), lk.Host)
  235. //write
  236. connClient.Write(b)
  237. if bodyLen, err := common.CopyBuffer(connClient, r.Body); err != nil {
  238. break
  239. } else {
  240. host.Flow.Add(int64(len(b))+bodyLen, 0)
  241. }
  242. reqCh <- r
  243. }
  244. end:
  245. if !readReq {
  246. s.writeConnFail(c.Conn)
  247. }
  248. c.Close()
  249. if target != nil {
  250. target.Close()
  251. }
  252. }
  253. func (s *httpServer) NewServer(port int, scheme string) *http.Server {
  254. return &http.Server{
  255. Addr: ":" + strconv.Itoa(port),
  256. Handler: http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
  257. r.URL.Scheme = scheme
  258. s.handleTunneling(w, r)
  259. }),
  260. // Disable HTTP/2.
  261. TLSNextProto: make(map[string]func(*http.Server, *tls.Conn, http.Handler)),
  262. }
  263. }