* Copyright (c) 2019 Huawei Technologies Co., Ltd.
* A-Tune is licensed under the Mulan PSL v2.
* You can use this software according to the terms and conditions of the Mulan PSL v2.
* You may obtain a copy of Mulan PSL v2 at:
* http://license.coscl.org.cn/MulanPSL2
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR
* PURPOSE.
* See the Mulan PSL v2 for more details.
* Create: 2019-10-29
*/
package http
import (
"bytes"
"crypto/tls"
"crypto/x509"
"encoding/json"
"encoding/pem"
"errors"
"fmt"
"io"
"io/ioutil"
"net/http"
"strings"
"gitee.com/openeuler/A-Tune/common/config"
)
type httpClient struct {
client *http.Client
}
func (c *httpClient) Do(req *http.Request) (*http.Response, error) {
response, err := c.client.Do(req)
return response, err
}
func VerifyCertificate(certFile string, pool *x509.CertPool) error {
certBytes, err := ioutil.ReadFile(certFile)
if err != nil {
return err
}
block, _ := pem.Decode(certBytes)
if block == nil {
return errors.New("failed to decode certificate")
}
cert, err := x509.ParseCertificate(block.Bytes)
if err != nil {
return errors.New("failed to parse certificate: " + err.Error())
}
opts := x509.VerifyOptions{
Roots: pool,
}
_, err = cert.Verify(opts)
if err != nil {
return errors.New("failed to verify certificate: " + err.Error())
}
return nil
}
func NewhttpClient(url string) (*httpClient, error) {
var client *http.Client
segs := strings.Split(url, "/")
if len(segs) < 5 {
return nil, fmt.Errorf("url: %s is not correct", url)
}
uri := segs[4]
if config.IsEnginePort(uri) && config.EngineTLS || !config.IsEnginePort(uri) && config.RestTLS {
pool := x509.NewCertPool()
caFile := config.TLSEngineCACertFile
if !config.IsEnginePort(uri) {
caFile = config.TLSRestCACertFile
}
caCrt, err := ioutil.ReadFile(caFile)
if err != nil {
return nil, err
}
pool.AppendCertsFromPEM(caCrt)
if err = VerifyCertificate(caFile, pool); err != nil {
return nil, err
}
clientCertFile := config.TLSEngineClientCertFile
clientKeyFile := config.TLSEngineClientKeyFile
if !config.IsEnginePort(uri) {
clientCertFile = config.TLSRestServerCertFile
clientKeyFile = config.TLSRestServerKeyFile
}
if err = VerifyCertificate(clientCertFile, pool); err != nil {
return nil, err
}
clientCrt, err := tls.LoadX509KeyPair(clientCertFile, clientKeyFile)
if err != nil {
return nil, err
}
tr := &http.Transport{
TLSClientConfig: &tls.Config{
RootCAs: pool,
Certificates: []tls.Certificate{clientCrt}},
}
client = &http.Client{Transport: tr}
} else {
client = &http.Client{}
}
return &httpClient{
client: client,
}, nil
}
func newRequest(method string, url string, body interface{}) (*http.Request, error) {
var reader io.Reader
switch t := body.(type) {
case string:
reader = strings.NewReader(body.(string))
case []byte:
reader = bytes.NewReader(body.([]byte))
default:
bytesData, err := json.Marshal(body)
if err != nil {
fmt.Printf("Error in Unexpected type %T\n", t)
return nil, err
}
reader = bytes.NewReader(bytesData)
}
request, err := http.NewRequest(method, url, reader)
if err != nil {
return nil, err
}
request.Header.Set("Content-Type", "application/x-www-form-urlencoded")
request.Header.Add("Content-Type", "application/json")
return request, nil
}
func Get(url string, data interface{}) (*http.Response, error) {
restClient, err := NewhttpClient(url)
if err != nil {
return nil, err
}
req, err := newRequest("GET", url, data)
if err != nil {
return nil, err
}
response, err := restClient.Do(req)
if err != nil {
return nil, err
}
return response, nil
}
func Post(url string, data interface{}) (*http.Response, error) {
restClient, err := NewhttpClient(url)
if err != nil {
return nil, err
}
req, err := newRequest("POST", url, data)
if err != nil {
return nil, err
}
response, err := restClient.Do(req)
if err != nil {
return nil, err
}
return response, nil
}
func Put(url string, data interface{}) (*http.Response, error) {
restClient, err := NewhttpClient(url)
if err != nil {
return nil, err
}
req, err := newRequest("PUT", url, data)
if err != nil {
return nil, err
}
response, err := restClient.Do(req)
if err != nil {
return nil, err
}
return response, nil
}
func Delete(url string) (*http.Response, error) {
restClient, err := NewhttpClient(url)
if err != nil {
return nil, err
}
req, err := newRequest("DELETE", url, nil)
if err != nil {
return nil, err
}
response, err := restClient.Do(req)
if err != nil {
return nil, err
}
return response, nil
}