hugegraph-client-go/hgtransport/hgtransport.go (165 lines of code) (raw):

/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with this * work for additional information regarding copyright ownership. The ASF * licenses this file to You under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package hgtransport import ( "bytes" "io/ioutil" "net/http" "net/url" "regexp" "runtime" "strings" "time" "github.com/apache/incubator-hugegraph-toolchain/hugegraph-client-go/internal/version" ) // Version returns the package version as a string. const Version = version.Client var ( userAgent string reGoVersion = regexp.MustCompile(`go(\d+\.\d+\..+)`) ) func init() { userAgent = initUserAgent() } // Interface defines the interface for HTTP client. type Interface interface { Perform(*http.Request) (*http.Response, error) GetConfig() Config } // Config represents the configuration of HTTP client. type Config struct { URL *url.URL Username string Password string GraphSpace string Graph string Transport http.RoundTripper Logger Logger } // Client represents the HTTP client. type Client struct { url *url.URL username string password string graphspace string graph string transport http.RoundTripper logger Logger } // New creates new HTTP client. // // http.DefaultTransport will be used if no transport is passed in the configuration. func New(cfg Config) *Client { if cfg.Transport == nil { cfg.Transport = http.DefaultTransport } return &Client{ url: cfg.URL, username: cfg.Username, password: cfg.Password, graphspace: cfg.GraphSpace, graph: cfg.Graph, transport: cfg.Transport, logger: cfg.Logger, } } func (c *Client) GetConfig() Config { return Config{ URL: c.url, Username: c.username, Password: c.password, GraphSpace: c.graphspace, Graph: c.graph, Transport: c.transport, Logger: nil, } } // Perform executes the request and returns a response or error. func (c *Client) Perform(req *http.Request) (*http.Response, error) { u := c.url c.setURL(u, req) c.setUserAgent(req) c.setHost(req) c.setContentTypeJSON(req) if _, ok := req.Header["Authorization"]; !ok { c.setBasicAuth(u, req) } var dupReqBody *bytes.Buffer if c.logger != nil && c.logger.RequestBodyEnabled() { if req.Body != nil && req.Body != http.NoBody { dupReqBody = bytes.NewBuffer(make([]byte, 0, int(req.ContentLength))) dupReqBody.ReadFrom(req.Body) req.Body = ioutil.NopCloser(bytes.NewBuffer(dupReqBody.Bytes())) } } start := time.Now().UTC() res, err := c.transport.RoundTrip(req) dur := time.Since(start) if c.logger == nil { return res, err } var dupRes http.Response if res != nil { dupRes = *res } if c.logger.RequestBodyEnabled() { if req.Body != nil && req.Body != http.NoBody { req.Body = ioutil.NopCloser(dupReqBody) } } if c.logger.ResponseBodyEnabled() { if res != nil && res.Body != nil && res.Body != http.NoBody { b1, b2, _ := duplicateBody(res.Body) dupRes.Body = b1 res.Body = b2 } } c.logger.LogRoundTrip(req, &dupRes, err, start, dur) // errcheck exclude return res, err } func (c *Client) setURL(u *url.URL, req *http.Request) *http.Request { req.URL.Scheme = u.Scheme req.URL.Host = u.Host if u.Path != "" { var b strings.Builder b.Grow(len(u.Path) + len(req.URL.Path)) b.WriteString(u.Path) b.WriteString(req.URL.Path) req.URL.Path = b.String() } return req } func (c *Client) setBasicAuth(u *url.URL, req *http.Request) *http.Request { if u.User != nil { password, _ := u.User.Password() req.SetBasicAuth(u.User.Username(), password) return req } if c.username != "" && c.password != "" { req.SetBasicAuth(c.username, c.password) return req } return req } func (c *Client) setUserAgent(req *http.Request) *http.Request { req.Header.Set("User-Agent", userAgent) return req } func (c *Client) setHost(req *http.Request) *http.Request { req.Header.Set("Host", req.URL.Host) return req } func (c *Client) setContentTypeJSON(req *http.Request) *http.Request { req.Header.Set("Content-Type", "application/json;charset=UTF-8") return req } func initUserAgent() string { var b strings.Builder b.WriteString("go-hugegraph") b.WriteRune('/') b.WriteString(Version) b.WriteRune(' ') b.WriteRune('(') b.WriteString(runtime.GOOS) b.WriteRune(' ') b.WriteString(runtime.GOARCH) b.WriteString("; ") b.WriteString("Go ") if v := reGoVersion.ReplaceAllString(runtime.Version(), "$1"); v != "" { b.WriteString(v) } else { b.WriteString(runtime.Version()) } b.WriteRune(')') return b.String() }