Reworks the protocol handling and makes html downloads work

This commit is contained in:
sloumdrone 2019-10-25 20:06:13 -07:00
parent e5c0bd7443
commit 67d7df6804
2 changed files with 261 additions and 177 deletions

152
client.go
View File

@ -514,6 +514,8 @@ func (c *client) saveFile(u Url, name string) {
file, err = gopher.Retrieve(u.Host, u.Port, u.Resource)
case "gemini":
file, err = gemini.Fetch(u.Host, u.Port, u.Resource, &c.Certs)
case "http", "https":
file, err = http.Fetch(u.Full)
default:
c.SetMessage(fmt.Sprintf("Saving files over %s is not supported", u.Scheme), true)
c.DrawMessage()
@ -737,6 +739,21 @@ func (c *client) Scroll(amount int) {
c.Draw()
}
func (c *client) ReloadPage() error {
if c.PageState.Length < 1 {
return fmt.Errorf("There is no page to reload")
}
url := c.PageState.History[c.PageState.Position].Location.Full
err := c.PageState.NavigateHistory(-1)
if err != nil {
return err
}
length := c.PageState.Length
c.Visit(url)
c.PageState.Length = length
return nil
}
func (c *client) SetPercentRead() {
page := c.PageState.History[c.PageState.Position]
var percentRead int
@ -834,6 +851,8 @@ func (c *client) SetHeaderUrl() {
}
}
// Visit functions as a controller/router to the
// appropriate protocol handler
func (c *client) Visit(url string) {
c.SetMessage("Loading...", false)
c.DrawMessage()
@ -848,6 +867,27 @@ func (c *client) Visit(url string) {
switch u.Scheme {
case "gopher":
c.handleGopher(u)
case "gemini":
c.handleGemini(u)
case "telnet":
c.handleTelnet(u)
case "http", "https":
c.handleWeb(u)
case "local":
c.handleLocal(u)
case "finger":
c.handleFinger(u)
default:
c.SetMessage(fmt.Sprintf("%q is not a supported protocol", u.Scheme), true)
c.DrawMessage()
}
}
// +++ Begin Protocol Handlers +++
func (c *client) handleGopher(u Url) {
if u.DownloadOnly {
nameSplit := strings.Split(u.Resource, "/")
filename := nameSplit[len(nameSplit)-1]
@ -873,7 +913,9 @@ func (c *client) Visit(url string) {
c.SetHeaderUrl()
c.Draw()
}
case "gemini":
}
func (c *client) handleGemini(u Url) {
capsule, err := gemini.Visit(u.Host, u.Port, u.Resource, &c.Certs)
if err != nil {
c.SetMessage(err.Error(), true)
@ -959,7 +1001,9 @@ func (c *client) Visit(url string) {
c.DrawMessage()
}
}
case "telnet":
}
func (c *client) handleTelnet(u Url) {
c.SetMessage("Attempting to start telnet session", false)
c.DrawMessage()
msg, err := telnet.StartSession(u.Host, u.Port)
@ -971,14 +1015,51 @@ func (c *client) Visit(url string) {
c.DrawMessage()
}
c.Draw()
case "http", "https":
}
func (c *client) handleLocal(u Url) {
content, err := local.Open(u.Resource)
if err != nil {
c.SetMessage(err.Error(), true)
c.DrawMessage()
return
}
pg := MakePage(u, content, []string{})
pg.WrapContent(c.Width - 1)
c.PageState.Add(pg)
c.SetPercentRead()
c.ClearMessage()
c.SetHeaderUrl()
c.Draw()
}
func (c *client) handleFinger(u Url) {
content, err := finger.Finger(u.Host, u.Port, u.Resource)
if err != nil {
c.SetMessage(err.Error(), true)
c.DrawMessage()
return
}
pg := MakePage(u, content, []string{})
pg.WrapContent(c.Width - 1)
c.PageState.Add(pg)
c.SetPercentRead()
c.ClearMessage()
c.SetHeaderUrl()
c.Draw()
}
func (c *client) handleWeb(u Url) {
// Following http is disabled
if strings.ToUpper(c.Options["openhttp"]) != "TRUE" {
c.SetMessage("'openhttp' is not set to true, cannot open web link", false)
c.DrawMessage()
return
}
switch strings.ToUpper(c.Options["lynxmode"]) {
case "TRUE":
// Use lynxmode
if strings.ToUpper(c.Options["lynxmode"]) == "TRUE" {
if http.IsTextFile(u.Full) {
page, err := http.Visit(u.Full, c.Width-1)
if err != nil {
c.SetMessage(fmt.Sprintf("Lynx error: %s", err.Error()), true)
@ -992,7 +1073,20 @@ func (c *client) Visit(url string) {
c.ClearMessage()
c.SetHeaderUrl()
c.Draw()
default:
} else {
c.SetMessage("The file is non-text: writing to disk...", false)
c.DrawMessage()
var fn string
if i := strings.LastIndex(u.Full, "/"); i > 0 && i + 1 < len(u.Full) {
fn = u.Full[i + 1:]
} else {
fn = "bombadillo.download"
}
c.saveFile(u, fn)
}
// Open in default web browser if available
} else {
if strings.ToUpper(c.Options["terminalonly"]) == "TRUE" {
c.SetMessage("'terminalonly' is set to true and 'lynxmode' is not enabled, cannot open web link", false)
c.DrawMessage()
@ -1008,54 +1102,8 @@ func (c *client) Visit(url string) {
c.DrawMessage()
}
}
case "local":
content, err := local.Open(u.Resource)
if err != nil {
c.SetMessage(err.Error(), true)
c.DrawMessage()
return
}
pg := MakePage(u, content, []string{})
pg.WrapContent(c.Width - 1)
c.PageState.Add(pg)
c.SetPercentRead()
c.ClearMessage()
c.SetHeaderUrl()
c.Draw()
case "finger":
content, err := finger.Finger(u.Host, u.Port, u.Resource)
if err != nil {
c.SetMessage(err.Error(), true)
c.DrawMessage()
return
}
pg := MakePage(u, content, []string{})
pg.WrapContent(c.Width - 1)
c.PageState.Add(pg)
c.SetPercentRead()
c.ClearMessage()
c.SetHeaderUrl()
c.Draw()
default:
c.SetMessage(fmt.Sprintf("%q is not a supported protocol", u.Scheme), true)
c.DrawMessage()
}
}
func (c *client) ReloadPage() error {
if c.PageState.Length < 1 {
return fmt.Errorf("There is no page to reload")
}
url := c.PageState.History[c.PageState.Position].Location.Full
err := c.PageState.NavigateHistory(-1)
if err != nil {
return err
}
length := c.PageState.Length
c.Visit(url)
c.PageState.Length = length
return nil
}
//------------------------------------------------\\
// + + + F U N C T I O N S + + + \\

View File

@ -2,6 +2,8 @@ package http
import (
"fmt"
"io/ioutil"
"net/http"
"os/exec"
"strings"
)
@ -23,6 +25,24 @@ func Visit(url string, width int) (page, error) {
return parseLinks(string(c)), nil
}
// Returns false on err or non-text type
// Else returns true
func IsTextFile(url string) bool {
c, err := exec.Command("lynx", "-dump", "-head", url).Output()
if err != nil {
return false
}
content := string(c)
content = strings.ToLower(content)
headers := strings.Split(content, "\n")
for _, header := range headers {
if strings.Contains(header, "content-type:") && strings.Contains(header, "text") {
return true
}
}
return false
}
func parseLinks(c string) page {
var out page
contentUntil := strings.LastIndex(c, "References")
@ -47,3 +67,19 @@ func parseLinks(c string) page {
return out
}
func Fetch(url string) ([]byte, error) {
resp, err := http.Get(url)
if err != nil {
return []byte{}, err
}
defer resp.Body.Close()
bodyBytes, err := ioutil.ReadAll(resp.Body)
if err != nil {
return []byte{}, err
}
return bodyBytes, nil
}