package gemini import ( "crypto/tls" "fmt" "net/url" "os" "strconv" "strings" ) const GeminiNetwork = "tcp" const GeminiPort = 1965 const GeminiPrefix = "gemini://" const requestSuffix = "\r\n" type GeminiURI struct { host string request []byte } func Parse(request, host string, port int) (*GeminiURI, error) { // add gemini:// scheme if missing if !strings.HasPrefix(request, GeminiPrefix) { request = GeminiPrefix + request } // create GeminiURI if host has been specified if strings.Contains(host, ":") { return &GeminiURI{host, []byte(request + requestSuffix)}, nil } else if host != "" { return &GeminiURI{host + ":" + strconv.Itoa(port), []byte(request + requestSuffix)}, nil } // get host from request u, err := url.Parse(request) if err != nil { return nil, err } if strings.Contains(u.Host, ":") { return &GeminiURI{u.Host, []byte(request + requestSuffix)}, nil } else { return &GeminiURI{u.Host + ":" + strconv.Itoa(port), []byte(request + requestSuffix)}, nil } } func (c *GeminiURI) Get(config *tls.Config, out *os.File) error { conn, err := tls.Dial(GeminiNetwork, c.host, config) if err != nil { return err } defer conn.Close() n, err := conn.Write(c.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 }