mirror of
https://github.com/aptly-dev/aptly.git
synced 2026-05-06 22:18:28 +00:00
Conver to regular Go vendor + dep tool
This commit is contained in:
+23
@@ -0,0 +1,23 @@
|
||||
# Compiled Object files, Static and Dynamic libs (Shared Objects)
|
||||
*.o
|
||||
*.a
|
||||
*.so
|
||||
|
||||
# Folders
|
||||
_obj
|
||||
_test
|
||||
|
||||
# Architecture specific extensions/prefixes
|
||||
*.[568vq]
|
||||
[568vq].out
|
||||
|
||||
*.cgo1.go
|
||||
*.cgo2.c
|
||||
_cgo_defun.c
|
||||
_cgo_gotypes.go
|
||||
_cgo_export.*
|
||||
|
||||
_testmain.go
|
||||
|
||||
*.exe
|
||||
*.test
|
||||
+21
@@ -0,0 +1,21 @@
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2014 Andrey Smirnov
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
+23
@@ -0,0 +1,23 @@
|
||||
go-ftp-protocol
|
||||
===============
|
||||
|
||||
Plugin for http.Transport with support for ftp:// protocol in Go.
|
||||
|
||||
Limitations: only anonymous FTP servers, only file retrieval operations.
|
||||
|
||||
Internally connections to FTP servers are cached and re-used when possible.
|
||||
|
||||
Example usage:
|
||||
|
||||
import "github.com/smira/go-ftp-protocol/protocol"
|
||||
|
||||
transport := &http.Transport{}
|
||||
transport.RegisterProtocol("ftp", &protocol.FTPRoundTripper{})
|
||||
|
||||
client := &http.Client{Transport: transport}
|
||||
|
||||
resp, err := client.Get("ftp://ftp.ru.debian.org/debian/README")
|
||||
|
||||
License: MIT
|
||||
|
||||
Base on FTP client library: http://github.com/jlaffaye/ftp/
|
||||
+152
@@ -0,0 +1,152 @@
|
||||
// Package protocol implements ftp:// scheme plugin for http.Transport
|
||||
//
|
||||
// github.com/jlaffaye/ftp library is used internally as FTP client implementation.
|
||||
//
|
||||
// Limitations: only anonymous FTP servers, only file retrieval operations.
|
||||
//
|
||||
// Internally connections to FTP servers are cached and re-used when possible.
|
||||
//
|
||||
// Example:
|
||||
//
|
||||
// transport := &http.Transport{}
|
||||
// transport.RegisterProtocol("ftp", &FTPRoundTripper{})
|
||||
// client := &http.Client{Transport: transport}
|
||||
// resp, err := client.Get("ftp://ftp.ru.debian.org/debian/README")
|
||||
package protocol
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/jlaffaye/ftp"
|
||||
"io"
|
||||
"net/http"
|
||||
"net/textproto"
|
||||
"strings"
|
||||
"sync"
|
||||
)
|
||||
|
||||
// FTPRoundTripper is an implementation of net/http.RoundTripper on top of FTP client
|
||||
type FTPRoundTripper struct {
|
||||
lock sync.Mutex
|
||||
idleConnections map[string][]*ftp.ServerConn
|
||||
}
|
||||
|
||||
// verify interface
|
||||
var (
|
||||
_ http.RoundTripper = &FTPRoundTripper{}
|
||||
)
|
||||
|
||||
type readCloserWrapper struct {
|
||||
body io.ReadCloser
|
||||
rt *FTPRoundTripper
|
||||
hostport string
|
||||
conn *ftp.ServerConn
|
||||
}
|
||||
|
||||
func (w *readCloserWrapper) Read(p []byte) (n int, err error) {
|
||||
return w.body.Read(p)
|
||||
}
|
||||
|
||||
func (w *readCloserWrapper) Close() error {
|
||||
err := w.body.Close()
|
||||
if err == nil {
|
||||
w.rt.putConnection(w.hostport, w.conn)
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
func (rt *FTPRoundTripper) getConnection(hostport string) (conn *ftp.ServerConn, err error) {
|
||||
rt.lock.Lock()
|
||||
conns, ok := rt.idleConnections[hostport]
|
||||
if ok && len(conns) > 0 {
|
||||
conn = conns[0]
|
||||
rt.idleConnections[hostport] = conns[1:]
|
||||
rt.lock.Unlock()
|
||||
return
|
||||
}
|
||||
rt.lock.Unlock()
|
||||
|
||||
conn, err = ftp.Connect(hostport)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
err = conn.Login("anonymous", "anonymous")
|
||||
if err != nil {
|
||||
conn.Quit()
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return conn, nil
|
||||
}
|
||||
|
||||
func (rt *FTPRoundTripper) putConnection(hostport string, conn *ftp.ServerConn) {
|
||||
rt.lock.Lock()
|
||||
defer rt.lock.Unlock()
|
||||
|
||||
if rt.idleConnections == nil {
|
||||
rt.idleConnections = make(map[string][]*ftp.ServerConn)
|
||||
}
|
||||
|
||||
rt.idleConnections[hostport] = append(rt.idleConnections[hostport], conn)
|
||||
}
|
||||
|
||||
// RoundTrip parses incoming GET "HTTP" request and transforms it into
|
||||
// commands to ftp client
|
||||
func (rt *FTPRoundTripper) RoundTrip(request *http.Request) (*http.Response, error) {
|
||||
if request.URL.Scheme != "ftp" {
|
||||
return nil, fmt.Errorf("only ftp protocol is supported, got %s", request.Proto)
|
||||
}
|
||||
|
||||
if request.Method != "GET" {
|
||||
return nil, fmt.Errorf("only GET method is supported, got %s", request.Method)
|
||||
}
|
||||
|
||||
hostport := request.URL.Host
|
||||
if strings.Index(hostport, ":") == -1 {
|
||||
hostport = hostport + ":21"
|
||||
}
|
||||
|
||||
connection, err := rt.getConnection(hostport)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var body io.ReadCloser
|
||||
body, err = connection.Retr(request.URL.Path)
|
||||
|
||||
if err != nil {
|
||||
if te, ok := err.(*textproto.Error); ok {
|
||||
rt.putConnection(hostport, connection)
|
||||
|
||||
if te.Code == ftp.StatusFileUnavailable {
|
||||
return &http.Response{
|
||||
Status: "404 Not Found",
|
||||
StatusCode: 404,
|
||||
Proto: "FTP/1.0",
|
||||
ProtoMajor: 1,
|
||||
ProtoMinor: 0,
|
||||
Request: request,
|
||||
}, nil
|
||||
}
|
||||
}
|
||||
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &http.Response{
|
||||
Status: "200 OK",
|
||||
StatusCode: 200,
|
||||
Proto: "FTP/1.0",
|
||||
ProtoMajor: 1,
|
||||
ProtoMinor: 0,
|
||||
Body: &readCloserWrapper{
|
||||
body: body,
|
||||
rt: rt,
|
||||
hostport: hostport,
|
||||
conn: connection,
|
||||
},
|
||||
ContentLength: -1,
|
||||
Request: request,
|
||||
}, nil
|
||||
}
|
||||
+94
@@ -0,0 +1,94 @@
|
||||
package protocol
|
||||
|
||||
import (
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestProtocol(t *testing.T) {
|
||||
transport := &http.Transport{}
|
||||
transport.RegisterProtocol("ftp", &FTPRoundTripper{})
|
||||
|
||||
client := &http.Client{Transport: transport}
|
||||
|
||||
resp, err := client.Get("ftp://ftp.ru.debian.org/debian/README")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if resp.StatusCode != 200 {
|
||||
t.Fatalf("resp.StatusCode 200 != %d", resp.StatusCode)
|
||||
}
|
||||
|
||||
content, err := ioutil.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
err = resp.Body.Close()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if !strings.HasPrefix(string(content), "See http://www.debian.org/ for information about Debian GNU/Linux.") {
|
||||
t.Fatalf("unexpected content: %s", content)
|
||||
}
|
||||
|
||||
resp, err = client.Get("ftp://ftp.ru.debian.org/debian/missing")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if resp.StatusCode != 404 {
|
||||
t.Fatalf("resp.StatusCode 404 != %d", resp.StatusCode)
|
||||
}
|
||||
}
|
||||
|
||||
func TestConcurrent(t *testing.T) {
|
||||
transport := &http.Transport{}
|
||||
transport.RegisterProtocol("ftp", &FTPRoundTripper{})
|
||||
|
||||
client := &http.Client{Transport: transport}
|
||||
|
||||
const concurrency = 4
|
||||
const count = 10
|
||||
|
||||
done := make(chan struct{}, concurrency)
|
||||
|
||||
for i := 0; i < concurrency; i++ {
|
||||
go func() {
|
||||
defer func() { done <- struct{}{} }()
|
||||
|
||||
for j := 0; j < 10; j++ {
|
||||
resp, err := client.Get("ftp://ftp.ru.debian.org/debian/README")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if resp.StatusCode != 200 {
|
||||
t.Fatalf("resp.StatusCode 200 != %d", resp.StatusCode)
|
||||
}
|
||||
|
||||
content, err := ioutil.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
err = resp.Body.Close()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if !strings.HasPrefix(string(content), "See http://www.debian.org/ for information about Debian GNU/Linux.") {
|
||||
t.Fatalf("unexpected content: %s", content)
|
||||
}
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
for i := 0; i < concurrency; i++ {
|
||||
<-done
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user