111 lines
2.3 KiB
Go
111 lines
2.3 KiB
Go
package main
|
|
|
|
import (
|
|
"bufio"
|
|
"fmt"
|
|
"io/ioutil"
|
|
"net"
|
|
"net/url"
|
|
"os"
|
|
"strconv"
|
|
"strings"
|
|
)
|
|
|
|
// A better url parser see:
|
|
// https://stackoverflow.com/questions/62083272/parsing-url-with-port-and-without-scheme
|
|
func ParseRawURL(rawurl string) (u *url.URL, err error) {
|
|
u, err := url.ParseRequestURI(rawurl)
|
|
if err != nil || u.Host == "" {
|
|
u, repErr := url.ParseRequestURI("https://" + rawurl)
|
|
if repErr != nil {
|
|
fmt.Printf("Could not parse raw url: %s, error: %v", rawurl, err)
|
|
u = nil
|
|
return
|
|
}
|
|
err = nil
|
|
return
|
|
}
|
|
|
|
return
|
|
}
|
|
|
|
// SpartanURL parses u and calls SpartanParsedURL with the parsed url
|
|
func SpartanURL(u string) bool {
|
|
parsed, err := ParseRawURL(u)
|
|
if err != nil {
|
|
return false
|
|
}
|
|
if parsed.Scheme != "spartan" {
|
|
fmt.Println("Unsupported scheme")
|
|
}
|
|
return SpartanParsedURL(*parsed)
|
|
}
|
|
|
|
// SpartanParsedURL fetches u and displays the page
|
|
func SpartanParsedURL(u url.URL) bool {
|
|
host := u.Host
|
|
// Connect to server
|
|
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: <program> [--help] [URL]")
|
|
return
|
|
}
|
|
// TODO: support multiple args
|
|
SpartanURL(args[1])
|
|
}
|