package util import ( "compress/gzip" "context" "crypto/x509" "encoding/json" "encoding/xml" "fmt" "io" "io/ioutil" "log" "net" "net/http" "os" "os/signal" "syscall" "time" "crypto/tls" ) const ( // RequestTimeOut http request timeout (second) RequestTimeOut = 30 ) // RouterHandler hander type RouterHandler struct { Method string Router string Hander http.Handler } // Message HTTP response type Message struct { StatusCode int Body []byte Header http.Header Cookies []*http.Cookie } func header(w io.Writer, contentType string) { w.(http.ResponseWriter).Header().Set(`Content-Type`, contentType) w.(http.ResponseWriter).Header().Set(`X-Powered-By`, LibName+`/`+LibVersion) w.(http.ResponseWriter).WriteHeader(http.StatusOK) } // Redirect redirect func Redirect(w http.ResponseWriter, url string) { w.Header().Set(`Location`, url) w.WriteHeader(http.StatusFound) } // GetRealIP get real IP from Request func GetRealIP(req *http.Request) (ip string) { if ips := req.Header["X-Real-Ip"]; ips != nil { ip = ips[0] } return } // WriteJSON response JSON data. func WriteJSON(w io.Writer, response interface{}) error { header(w, `application/json; charset=utf-8`) return json.NewEncoder(w).Encode(response) } // WriteXML response XML data. func WriteXML(w http.ResponseWriter, response interface{}) error { header(w, `application/xml; charset=utf-8`) return xml.NewEncoder(w).Encode(response) } // WriteBytes response bytes func WriteBytes(w http.ResponseWriter, response interface{}) error { header(w, `text/html; charset=utf-8`) w.Write(response.([]byte)) return nil } // WriteBytesContentType response bytes and Content-Type func WriteBytesContentType(w http.ResponseWriter, response interface{}, contentType string) error { header(w, contentType) w.Write(response.([]byte)) return nil } // WriteCtxJSON response JSON data. func WriteCtxJSON(ctx context.Context, w http.ResponseWriter, response interface{}) error { return WriteJSON(w, response) } // WriteCtxXML response XML data. func WriteCtxXML(ctx context.Context, w http.ResponseWriter, response interface{}) error { return WriteXML(w, response) } // WriteCtxBytes response text data. func WriteCtxBytes(ctx context.Context, w http.ResponseWriter, response interface{}) error { return WriteBytes(w, response) } // ResponseJSON reply JSON func ResponseJSON(reply *ReplyData, err error, req *http.Request, w http.ResponseWriter) error { if err != nil { return WriteJSON(w, ErrReplyData(ErrException, err.Error())) } return WriteJSON(w, reply) } // HTTPListenAndServe new server and start func HTTPListenAndServe(addr string, router http.Handler) { server := &http.Server{ Addr: addr, Handler: router, ReadTimeout: 30 * time.Second, WriteTimeout: 30 * time.Second, MaxHeaderBytes: 1 << 20, } // Interrupt handler. errc := make(chan error) go func() { c := make(chan os.Signal) signal.Notify(c, syscall.SIGINT, syscall.SIGTERM) errc <- fmt.Errorf("%s", <-c) }() // HTTP transport. go func() { log.Println("HTTP Server listen on", addr) //logger.Log("Protocol", "HTTP", "addr", addr) errc <- server.ListenAndServe() log.Println("Exit HTTP server", "Quit") }() // Run! log.Println("Exit", <-errc) } // newHTTPRequest http request func newHTTPRequest(method, uri, certPath, keyPath string, header map[string]string, cookies []*http.Cookie, body io.Reader) (res *http.Response, err error) { t := &http.Transport{ Dial: func(netw, addr string) (net.Conn, error) { conn, err := net.DialTimeout(netw, addr, time.Second*RequestTimeOut) if err != nil { return nil, err } conn.SetDeadline(time.Now().Add(time.Second * RequestTimeOut)) return conn, nil }, ResponseHeaderTimeout: time.Second * RequestTimeOut, } if certPath != "" { cert, e := tls.LoadX509KeyPair(certPath, keyPath) if e != nil { t.TLSClientConfig = &tls.Config{InsecureSkipVerify: true} } else { pool := x509.NewCertPool() t.TLSClientConfig = &tls.Config{InsecureSkipVerify: true, Certificates: []tls.Certificate{cert}, RootCAs: pool} } } client := &http.Client{Transport: t} var ( req *http.Request ) if cookies != nil { } if body != nil { req, err = http.NewRequest(method, uri, body) } else { req, err = http.NewRequest(method, uri, nil) } if err != nil { return } for k := range header { req.Header.Add(k, header[k]) } res, err = client.Do(req) return } func readBody(res *http.Response) (msg Message, err error) { var ( body []byte reader io.Reader ) encoding := res.Header.Get("Content-Encoding") switch encoding { case "gzip": reader, err = gzip.NewReader(res.Body) if err == nil { body, err = ioutil.ReadAll(reader) } default: body, err = ioutil.ReadAll(res.Body) } if err != nil { return } msg.StatusCode = res.StatusCode msg.Header = res.Header msg.Body = body return } // Post HTTP request POST func Post(uri, certPath, keyPath string, header map[string]string, data io.Reader) (msg Message, err error) { var res *http.Response if res, err = newHTTPRequest("POST", uri, certPath, keyPath, header, nil, data); err != nil { return } defer res.Body.Close() msg, err = readBody(res) msg.Cookies = res.Cookies() return } // Get HTTP request GET func Get(uri, certPath, keyPath string, header map[string]string) (msg Message, err error) { var res *http.Response if res, err = newHTTPRequest("GET", uri, certPath, keyPath, header, nil, nil); err != nil { return } defer res.Body.Close() msg, err = readBody(res) msg.Cookies = res.Cookies() return } // SetCookie set http cookie func SetCookie(w http.ResponseWriter, name, value, path string, maxAge int) { cookie := &http.Cookie{ Name: name, Value: value, Path: path, HttpOnly: false, MaxAge: maxAge} http.SetCookie(w, cookie) }