Codebase list golang-github-tv42-httpunix / upstream/0.0_git20150427.b75d861
New upstream version 0.0~git20150427.b75d861 Dmitry Smirnov 4 years ago
4 changed file(s) with 193 addition(s) and 0 deletion(s). Raw diff Collapse all Expand all
0 *.test
0 Copyright (c) 2013-2015 Tommi Virtanen.
1
2 Permission is hereby granted, free of charge, to any person obtaining a copy
3 of this software and associated documentation files (the "Software"), to deal
4 in the Software without restriction, including without limitation the rights
5 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
6 copies of the Software, and to permit persons to whom the Software is
7 furnished to do so, subject to the following conditions:
8
9 The above copyright notice and this permission notice shall be included in
10 all copies or substantial portions of the Software.
11
12 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
13 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
14 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
15 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
16 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
17 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
18 THE SOFTWARE.
0 // Package httpunix provides a HTTP transport (net/http.RoundTripper)
1 // that uses Unix domain sockets instead of HTTP.
2 //
3 // This is useful for non-browser connections within the same host, as
4 // it allows using the file system for credentials of both client
5 // and server, and guaranteeing unique names.
6 //
7 // The URLs look like this:
8 //
9 // http+unix://LOCATION/PATH_ETC
10 //
11 // where LOCATION is translated to a file system path with
12 // Transport.RegisterLocation, and PATH_ETC follow normal http: scheme
13 // conventions.
14 package httpunix
15
16 import (
17 "bufio"
18 "errors"
19 "net"
20 "net/http"
21 "sync"
22 "time"
23 )
24
25 // Scheme is the URL scheme used for HTTP over UNIX domain sockets.
26 const Scheme = "http+unix"
27
28 // Transport is a http.RoundTripper that connects to Unix domain
29 // sockets.
30 type Transport struct {
31 DialTimeout time.Duration
32 RequestTimeout time.Duration
33 ResponseHeaderTimeout time.Duration
34
35 mu sync.Mutex
36 // map a URL "hostname" to a UNIX domain socket path
37 loc map[string]string
38 }
39
40 // RegisterLocation registers an URL location and maps it to the given
41 // file system path.
42 //
43 // Calling RegisterLocation twice for the same location is a
44 // programmer error, and causes a panic.
45 func (t *Transport) RegisterLocation(loc string, path string) {
46 t.mu.Lock()
47 defer t.mu.Unlock()
48 if t.loc == nil {
49 t.loc = make(map[string]string)
50 }
51 if _, exists := t.loc[loc]; exists {
52 panic("location " + loc + " already registered")
53 }
54 t.loc[loc] = path
55 }
56
57 var _ http.RoundTripper = (*Transport)(nil)
58
59 // RoundTrip executes a single HTTP transaction. See
60 // net/http.RoundTripper.
61 func (t *Transport) RoundTrip(req *http.Request) (*http.Response, error) {
62 if req.URL == nil {
63 return nil, errors.New("http+unix: nil Request.URL")
64 }
65 if req.URL.Scheme != Scheme {
66 return nil, errors.New("unsupported protocol scheme: " + req.URL.Scheme)
67 }
68 if req.URL.Host == "" {
69 return nil, errors.New("http+unix: no Host in request URL")
70 }
71 t.mu.Lock()
72 path, ok := t.loc[req.URL.Host]
73 t.mu.Unlock()
74 if !ok {
75 return nil, errors.New("unknown location: " + req.Host)
76 }
77
78 c, err := net.DialTimeout("unix", path, t.DialTimeout)
79 if err != nil {
80 return nil, err
81 }
82 r := bufio.NewReader(c)
83 if t.RequestTimeout > 0 {
84 c.SetWriteDeadline(time.Now().Add(t.RequestTimeout))
85 }
86 if err := req.Write(c); err != nil {
87 return nil, err
88 }
89 if t.ResponseHeaderTimeout > 0 {
90 c.SetReadDeadline(time.Now().Add(t.ResponseHeaderTimeout))
91 }
92 resp, err := http.ReadResponse(r, req)
93 return resp, err
94 }
0 package httpunix_test
1
2 import (
3 "fmt"
4 "log"
5 "net"
6 "net/http"
7 "net/http/httputil"
8 "time"
9
10 "github.com/tv42/httpunix"
11 )
12
13 func Example_clientStandalone() {
14 // This example shows using a customized http.Client.
15 u := &httpunix.Transport{
16 DialTimeout: 100 * time.Millisecond,
17 RequestTimeout: 1 * time.Second,
18 ResponseHeaderTimeout: 1 * time.Second,
19 }
20 u.RegisterLocation("myservice", "/path/to/socket")
21
22 var client = http.Client{
23 Transport: u,
24 }
25
26 resp, err := client.Get("http+unix://myservice/urlpath/as/seen/by/server")
27 if err != nil {
28 log.Fatal(err)
29 }
30 buf, err := httputil.DumpResponse(resp, true)
31 if err != nil {
32 log.Fatal(err)
33 }
34 fmt.Printf("%s", buf)
35 resp.Body.Close()
36 }
37
38 func Example_clientIntegrated() {
39 // This example shows handling all net/http requests for the
40 // http+unix URL scheme.
41 u := &httpunix.Transport{
42 DialTimeout: 100 * time.Millisecond,
43 RequestTimeout: 1 * time.Second,
44 ResponseHeaderTimeout: 1 * time.Second,
45 }
46 u.RegisterLocation("myservice", "/path/to/socket")
47
48 // If you want to use http: with the same client:
49 t := &http.Transport{}
50 t.RegisterProtocol(httpunix.Scheme, u)
51 var client = http.Client{
52 Transport: t,
53 }
54
55 resp, err := client.Get("http+unix://myservice/urlpath/as/seen/by/server")
56 if err != nil {
57 log.Fatal(err)
58 }
59 buf, err := httputil.DumpResponse(resp, true)
60 if err != nil {
61 log.Fatal(err)
62 }
63 fmt.Printf("%s", buf)
64 resp.Body.Close()
65 }
66
67 func Example_server() {
68 l, err := net.Listen("unix", "/path/to/socket")
69 if err != nil {
70 log.Fatal(err)
71 }
72 defer l.Close()
73
74 if err := http.Serve(l, nil); err != nil {
75 log.Fatal(err)
76 }
77 }