Skip to content
This repository was archived by the owner on Dec 20, 2024. It is now read-only.

Commit 2086f69

Browse files
add implementation of http/https protocol
Signed-off-by: allen.wq <[email protected]>
1 parent 54f0a67 commit 2086f69

File tree

6 files changed

+605
-0
lines changed

6 files changed

+605
-0
lines changed

pkg/protocol/http/http.go

Lines changed: 191 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,191 @@
1+
/*
2+
* Copyright The Dragonfly Authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package http
18+
19+
import (
20+
"crypto/tls"
21+
"fmt"
22+
"net"
23+
"net/http"
24+
"time"
25+
26+
"github.com/dragonflyoss/Dragonfly/pkg/errortypes"
27+
"github.com/dragonflyoss/Dragonfly/pkg/protocol"
28+
)
29+
30+
var (
31+
// DefaultTransport is default implementation of http.Transport.
32+
DefaultTransport = newDefaultTransport()
33+
34+
// DefaultClient is default implementation of Client.
35+
DefaultClient = &Client{
36+
client: &http.Client{Transport: DefaultTransport},
37+
transport: DefaultTransport,
38+
}
39+
)
40+
41+
const (
42+
// http protocol name
43+
ProtocolHTTPName = "http"
44+
45+
// https protocol name
46+
ProtocolHTTPSName = "https"
47+
)
48+
49+
func init() {
50+
protocol.RegisterProtocol(ProtocolHTTPName, &ClientBuilder{})
51+
protocol.RegisterProtocol(ProtocolHTTPSName, &ClientBuilder{supportHTTPS: true})
52+
}
53+
54+
const (
55+
HTTPTransport = "http.transport"
56+
TLSConfig = "tls.config"
57+
)
58+
59+
func newDefaultTransport() *http.Transport {
60+
// copy from http.DefaultTransport
61+
return &http.Transport{
62+
Proxy: http.ProxyFromEnvironment,
63+
DialContext: (&net.Dialer{
64+
Timeout: 30 * time.Second,
65+
KeepAlive: 30 * time.Second,
66+
DualStack: true,
67+
}).DialContext,
68+
MaxIdleConns: 100,
69+
IdleConnTimeout: 90 * time.Second,
70+
TLSHandshakeTimeout: 10 * time.Second,
71+
ExpectContinueTimeout: 1 * time.Second,
72+
}
73+
}
74+
75+
// ClientOpt is the argument of NewProtocolClient.
76+
// ClientOpt supports some opt by key, such as "http.transport", "tls.config".
77+
// if not set, default opt will be used.
78+
type ClientOpt struct {
79+
opt map[string]interface{}
80+
}
81+
82+
func NewClientOpt() *ClientOpt {
83+
return &ClientOpt{
84+
opt: make(map[string]interface{}),
85+
}
86+
}
87+
88+
func (opt *ClientOpt) Set(key string, value interface{}) error {
89+
switch key {
90+
case HTTPTransport:
91+
if _, ok := value.(*http.Transport); !ok {
92+
return errortypes.ErrConvertFailed
93+
}
94+
break
95+
case TLSConfig:
96+
if _, ok := value.(*tls.Config); !ok {
97+
return errortypes.ErrConvertFailed
98+
}
99+
break
100+
default:
101+
return fmt.Errorf("not support")
102+
}
103+
104+
opt.opt[key] = value
105+
return nil
106+
}
107+
108+
func (opt *ClientOpt) Get(key string) interface{} {
109+
v, ok := opt.opt[key]
110+
if !ok {
111+
return nil
112+
}
113+
114+
return v
115+
}
116+
117+
var _ protocol.Client = &Client{}
118+
119+
// Client is an implementation of protocol.Client for http protocol.
120+
type Client struct {
121+
client *http.Client
122+
transport http.RoundTripper
123+
}
124+
125+
func (cli *Client) GetResource(url string, md protocol.Metadata) protocol.Resource {
126+
var (
127+
hd *Headers
128+
)
129+
130+
if md != nil {
131+
h, ok := md.(*Headers)
132+
if ok {
133+
hd = h
134+
}
135+
}
136+
137+
return &Resource{
138+
url: url,
139+
hd: hd,
140+
client: cli,
141+
}
142+
}
143+
144+
// ClientBuilder is an implementation of protocol.ClientBuilder for http protocol.
145+
type ClientBuilder struct {
146+
supportHTTPS bool
147+
}
148+
149+
func (cb *ClientBuilder) NewProtocolClient(clientOpt interface{}) (protocol.Client, error) {
150+
var (
151+
transport *http.Transport = DefaultTransport
152+
tlsConfig *tls.Config
153+
)
154+
155+
if clientOpt != nil {
156+
opt, ok := clientOpt.(*ClientOpt)
157+
if !ok {
158+
return nil, errortypes.ErrConvertFailed
159+
}
160+
161+
tran := opt.Get(HTTPTransport)
162+
if tran != nil {
163+
transport = tran.(*http.Transport)
164+
}
165+
166+
config := opt.Get(TLSConfig)
167+
if config != nil {
168+
tlsConfig = config.(*tls.Config)
169+
}
170+
171+
// set tls config to transport
172+
if config != nil {
173+
if transport == DefaultTransport {
174+
transport = newDefaultTransport()
175+
}
176+
177+
transport.TLSClientConfig = tlsConfig
178+
}
179+
}
180+
181+
if cb.supportHTTPS {
182+
if transport.TLSClientConfig == nil || transport.DialTLS == nil {
183+
return nil, fmt.Errorf("in https mode, tls should be set")
184+
}
185+
}
186+
187+
return &Client{
188+
client: &http.Client{Transport: transport},
189+
transport: transport,
190+
}, nil
191+
}

pkg/protocol/http/md.go

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
/*
2+
* Copyright The Dragonfly Authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package http
18+
19+
import (
20+
"net/http"
21+
22+
"github.com/dragonflyoss/Dragonfly/pkg/protocol"
23+
)
24+
25+
// NewHTTPMetaData generates an instance of protocol.Metadata.
26+
func NewHTTPMetaData() protocol.Metadata {
27+
return &Headers{
28+
Header: make(http.Header),
29+
}
30+
}
31+
32+
// Headers is an implementation of protocol.Metadata.
33+
type Headers struct {
34+
http.Header
35+
}
36+
37+
func (hd *Headers) Get(key string) (interface{}, error) {
38+
return hd.Header.Get(key), nil
39+
}
40+
41+
func (hd *Headers) Set(key string, value interface{}) {
42+
hd.Header.Set(key, value.(string))
43+
}
44+
45+
func (hd *Headers) Del(key string) {
46+
hd.Header.Del(key)
47+
}
48+
49+
func (hd *Headers) All() interface{} {
50+
return hd.Header
51+
}

pkg/protocol/http/md_test.go

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
/*
2+
* Copyright The Dragonfly Authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package http
18+
19+
import (
20+
"net/http"
21+
"testing"
22+
23+
"github.com/dragonflyoss/Dragonfly/dfget/core/helper"
24+
25+
"github.com/go-check/check"
26+
)
27+
28+
func Test(t *testing.T) {
29+
check.TestingT(t)
30+
}
31+
32+
type HTTPSuite struct {
33+
host string
34+
port int
35+
server *helper.MockFileServer
36+
}
37+
38+
func init() {
39+
check.Suite(&HTTPSuite{})
40+
}
41+
42+
func (suite *HTTPSuite) TestMd(c *check.C) {
43+
md := NewHTTPMetaData()
44+
md.Set("k1", "v1")
45+
md.Set("k2", "v2")
46+
47+
v1, err := md.Get("k1")
48+
c.Assert(err, check.IsNil)
49+
c.Assert(v1.(string), check.Equals, "v1")
50+
51+
v2, err := md.Get("k2")
52+
c.Assert(err, check.IsNil)
53+
c.Assert(v2.(string), check.Equals, "v2")
54+
55+
md.Del("k1")
56+
v1, err = md.Get("k1")
57+
c.Assert(err, check.IsNil)
58+
c.Assert(v1.(string), check.Equals, "")
59+
60+
hd, ok := md.All().(http.Header)
61+
c.Assert(ok, check.Equals, true)
62+
63+
v2 = hd.Get("k2")
64+
c.Assert(v2, check.Equals, "v2")
65+
}

0 commit comments

Comments
 (0)