package main import ( "bufio" "fmt" "io/ioutil" "net" "net/url" "os" "strconv" "strings" ) // SpartanURL parses u and calls SpartanParsedURL with the parsed url func SpartanURL(u string) bool { // Parse URL parsed, err := url.Parse(u) if err != nil { fmt.Println("invalid url") return false } if parsed.Scheme == "" { // have to parse again // ignoring err since it shouldn't fail here if it succeeded above parsed, _ = url.Parse("spartan://" + u) } if parsed.Scheme != "spartan" { fmt.Printf("Unsupported scheme %s", parsed.Scheme) return false } return SpartanParsedURL(*parsed) } // SpartanParsedURL fetches u and displays the page func SpartanParsedURL(u url.URL) bool { host := u.Host // Connect to server if u.Port() == "" { host += ":300" } conn, err := net.Dial("tcp", host) if err != nil { fmt.Println("unable to connect to " + u.Host) fmt.Println(err.Error()) return false } defer conn.Close() // Send request path := u.Path if u.Path == "" { path = "/" } conn.Write([]byte(fmt.Sprintf("%s %s 0\r\n", u.Hostname(), path))) // Receive and parse response header reader := bufio.NewReader(conn) header, err := reader.ReadString(byte('\n')) if err != nil { fmt.Println("Error reading response header") return false } // Parse header statusParts := strings.SplitN(header, " ", 2) status, err := strconv.Atoi(statusParts[0]) if err != nil { fmt.Println("invalid status code:" + statusParts[0]) return false } meta := statusParts[1] // Handle status switch status { case 1: fmt.Println("[INPUT]") fmt.Println(meta) case 2: // TODO: handle mime type bodyBytes, err := ioutil.ReadAll(reader) if err != nil { fmt.Println("Error reading body") return false } body := string(bodyBytes) fmt.Print(body) case 3: SpartanURL("spartan://" + u.Host + meta) case 4: fmt.Println("Error: " + meta) case 5: fmt.Println("Server error: " + meta) } return true } func main() { args := os.Args if len(args) == 0 || args[1] == "--help" { fmt.Println("Usage: [--help] [URL]") return } // TODO: support multiple args SpartanURL(args[1]) }