diff options
author | aqua <aqua@iserlohn-fortress.net> | 2021-07-29 16:11:39 +0300 |
---|---|---|
committer | aqua <aqua@iserlohn-fortress.net> | 2021-07-29 16:11:39 +0300 |
commit | e1174b74985e33c7123cb9cd8edf3601e4026053 (patch) | |
tree | cf0c66591a8943779e8b0f04ebf0d283c80a715d | |
parent | Properly get hostname from requests (diff) | |
download | gemcat-e1174b74985e33c7123cb9cd8edf3601e4026053.tar.xz |
Split off Gemini code into gemini.go
-rw-r--r-- | gemini.go | 82 | ||||
-rw-r--r-- | gemini_test.go | 43 | ||||
-rw-r--r-- | main.go | 69 |
3 files changed, 135 insertions, 59 deletions
diff --git a/gemini.go b/gemini.go new file mode 100644 index 0000000..8594de4 --- /dev/null +++ b/gemini.go @@ -0,0 +1,82 @@ +package main + +import ( + "crypto/tls" + "fmt" + "net/url" + "os" + "strconv" + "strings" +) + +const GeminiNetwork = "tcp" +const GeminiPort = 1965 +const GeminiPrefix = "gemini://" + +func FormatRequest(request string) []byte { + if !strings.HasPrefix(request, GeminiPrefix) { + request = GeminiPrefix + request + } + request = request + "\r\n" + return []byte(request) +} + +type GeminiConn struct { + host string + config *tls.Config +} + +func NewGeminiConn(request string, port int) (*GeminiConn, error) { + if !strings.HasPrefix(request, "gemini://") { + request = "gemini://" + request + } + + u, err := url.Parse(request) + if err != nil { + return nil, err + } + + conf := tls.Config{ + InsecureSkipVerify: true, + } + + if strings.Contains(u.Host, ":") { + return &GeminiConn{u.Host, &conf}, nil + } else { + return &GeminiConn{u.Host + ":" + strconv.Itoa(port), &conf}, nil + } +} + +func (c *GeminiConn) Get(request []byte, out *os.File) error { + conn, err := tls.Dial(GeminiNetwork, c.host, c.config) + if err != nil { + return err + } + defer conn.Close() + + n, err := conn.Write(request) + if err != nil { + return err + } + + buf := make([]byte, 1024) + + for { + n, err = conn.Read(buf) + if err != nil { + return err + } + written, err := out.Write(buf[:n]) + if written != n { + return fmt.Errorf("Got %d bytes, but only wrote %d bytes", n, written) + } + if err != nil { + return err + } + + if n == 0 { + break + } + } + return nil +} diff --git a/gemini_test.go b/gemini_test.go new file mode 100644 index 0000000..e029c04 --- /dev/null +++ b/gemini_test.go @@ -0,0 +1,43 @@ +package main + +import ( + "bytes" + "strconv" + "testing" +) + +func TestNewGeminiConn(t *testing.T) { + tables := []struct { + url string + port int + host string + }{ + {"hostname.com", GeminiPort, "hostname.com:" + strconv.Itoa(GeminiPort)}, + {"hostname.com", 1234, "hostname.com:1234"}, + } + + for _, table := range tables { + conn, err := NewGeminiConn(table.url, table.port) + if err != nil { + t.Fatalf("NewGeminiConn error: %s", err.Error()) + } + if conn.host != table.host { + t.Fatalf("NewGeminiConn error: wrong hostname %s", conn.host) + } + } +} + +func TestFormatRequest(t *testing.T) { + tables := []struct { + input string + output []byte + }{ + {"hostname.com", []byte("gemini://hostname.com\r\n")}, + } + + for _, table := range tables { + if !bytes.Equal(FormatRequest(table.input), table.output) { + t.Fatalf("FormatRequest failed on: %s\n", table.input) + } + } +} @@ -1,29 +1,14 @@ package main import ( - "crypto/tls" "flag" "fmt" "log" - "net/url" "os" - "strconv" - "strings" ) -var port = 1965 - -func get_host(path string) (string, error) { - if !strings.HasPrefix(path, "gemini://") { - path = "gemini://" + path - } - url, err := url.Parse(path) - if err != nil { - return "", err - } - - return url.Host + ":" + strconv.Itoa(port), nil -} +var host = "" +var port = GeminiPort func usage() { fmt.Printf("Usage: %s [options] url\n", os.Args[0]) @@ -32,7 +17,10 @@ func usage() { func main() { flag.Usage = usage + flag.StringVar(&host, "h", host, "server host name") + flag.StringVar(&host, "host", host, "server host name") flag.IntVar(&port, "p", port, "server port number") + flag.IntVar(&port, "port", port, "server port number") flag.Parse() if flag.NArg() != 1 { fmt.Printf("Got %d arguments, expected 1\n", flag.NArg()) @@ -40,52 +28,15 @@ func main() { os.Exit(1) } - url, err := get_host(flag.Arg(0)) - if err != nil { - panic("Error parsing hostname: " + err.Error()) - } - request := flag.Arg(0) + "\r\n" - if !strings.HasPrefix(request, "gemini://") { - request = "gemini://" + request - } - - conf := tls.Config{ - InsecureSkipVerify: true, - } - - log.Println("connecting to: " + url) - log.Println("request: " + request) - - conn, err := tls.Dial("tcp", url, &conf) - + conn, err := NewGeminiConn(flag.Arg(0), port) if err != nil { - panic("failed to connect: " + err.Error()) - } else { - log.Println("connected to " + url) + log.Fatalf("Error parsing hostname: %s\n", err.Error()) } - defer conn.Close() + log.Printf("connecting to: %s\n", conn.host) - n, err := conn.Write([]byte(request)) + err = conn.Get(FormatRequest(flag.Arg(0)), os.Stdout) if err != nil { - log.Println(n, err) - return + log.Fatalf("Error: %s\n", err.Error()) } - - buf := make([]byte, 1024) - - for { - n, err = conn.Read(buf) - if err != nil { - log.Println(n, err) - return - } else { - println(string(buf[:n])) - } - - if n == 0 { - break - } - } - } |