Browse Source

http web server & client

ls 5 years ago
parent
commit
0d9919ecf4
2 changed files with 251 additions and 0 deletions
  1. 117 0
      web/client.go
  2. 134 0
      web/server.go

+ 117 - 0
web/client.go

@@ -0,0 +1,117 @@
+package web
+
+import (
+	"compress/gzip"
+	"crypto/tls"
+	"crypto/x509"
+	"io"
+	"io/ioutil"
+	"net"
+	"net/http"
+	"time"
+)
+
+const (
+	// RequestTimeOut http request timeout (second)
+	RequestTimeOut = 30
+)
+
+// Message HTTP response
+type Message struct {
+	StatusCode int
+	Body       []byte
+	Header     http.Header
+}
+
+func newRequest(method, uri, certPath, keyPath string, header map[string]string, 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 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 = newRequest("POST", uri, certPath, keyPath, header, data); err != nil {
+		return
+	}
+	defer res.Body.Close()
+	msg, err = readBody(res)
+	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 = newRequest("GET", uri, certPath, keyPath, header, nil); err != nil {
+		return
+	}
+
+	defer res.Body.Close()
+	msg, err = readBody(res)
+	return
+}

+ 134 - 0
web/server.go

@@ -0,0 +1,134 @@
+package web
+
+import (
+	"context"
+	"encoding/json"
+	"encoding/xml"
+	"fmt"
+	"log"
+	"net/http"
+	"os"
+	"os/signal"
+	"syscall"
+	"time"
+
+	"git.chuangxin1.com/cx/tyr"
+)
+
+func header(w http.ResponseWriter, contentType string) {
+	w.Header().Set(`Content-Type`, contentType)
+	w.Header().Set(`X-Powered-By`, tyr.LibName+`/`+tyr.LibVersion)
+	w.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
+}
+
+// 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)
+}
+
+// WriteJSON response JSON data.
+func WriteJSON(w http.ResponseWriter, 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
+}
+
+// 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 *tyr.ReplyData, req *http.Request, w http.ResponseWriter) error {
+	return WriteJSON(w, reply)
+}
+
+func newServe(addr string, router http.Handler) *http.Server {
+	return &http.Server{
+		Addr:           addr,
+		Handler:        router,
+		ReadTimeout:    30 * time.Second,
+		WriteTimeout:   30 * time.Second,
+		MaxHeaderBytes: 1 << 20,
+	}
+}
+
+// ListenAndServe new server and start
+func ListenAndServe(addr string, router http.Handler) {
+	s := newServe(addr, router)
+	errc := make(chan error)
+	go func() {
+		c := make(chan os.Signal)
+		signal.Notify(c, syscall.SIGINT, syscall.SIGTERM)
+		errc <- fmt.Errorf("%s", <-c)
+	}()
+
+	go func() {
+		log.Println("HTTP Server listen on", addr)
+		errc <- s.ListenAndServe()
+		log.Println("Exit HTTP server", "Quit")
+	}()
+	log.Println("Exit", <-errc)
+}
+
+// ListenAndServeTLS new server and start
+func ListenAndServeTLS(addr, certFile, keyFile string, router http.Handler) {
+	s := newServe(addr, router)
+
+	errc := make(chan error)
+	go func() {
+		c := make(chan os.Signal)
+		signal.Notify(c, syscall.SIGINT, syscall.SIGTERM)
+		errc <- fmt.Errorf("%s", <-c)
+	}()
+
+	go func() {
+		log.Println("HTTP Server listen on", addr)
+		errc <- s.ListenAndServeTLS(certFile, keyFile)
+		log.Println("Exit HTTP server", "Quit")
+	}()
+	log.Println("Exit", <-errc)
+}