You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
134 lines
3.5 KiB
Go
134 lines
3.5 KiB
Go
package gopher
|
|
|
|
import (
|
|
"gophi/core"
|
|
"os"
|
|
"strings"
|
|
)
|
|
|
|
var (
|
|
// Gophermap formatting globals
|
|
subgophermapSizeMax int64
|
|
pageWidth int
|
|
footer []byte
|
|
)
|
|
|
|
// serve is the global gopher server's serve function
|
|
func serve(client *core.Client) {
|
|
// Receive line from client
|
|
received, err := client.Conn().ReadLine()
|
|
if err != nil {
|
|
client.LogError("Conn read fail")
|
|
handleError(client, err)
|
|
return
|
|
}
|
|
|
|
// Split up to first tab in case we've been
|
|
// given index search query (which we use to set CGI env),
|
|
// or extra Gopher+ information (which we don't care about)
|
|
raw, extra := core.SplitBy(string(received), "\t")
|
|
|
|
// Ensure we've received a valid URL string
|
|
if core.HasAsciiControlBytes(raw) {
|
|
client.LogError("Invalid request: %s", raw)
|
|
handleError(client, core.ErrInvalidRequest.Extendf("%s has ascii control bytes", raw))
|
|
return
|
|
}
|
|
|
|
// Parse the encoded URI into path and query components
|
|
path, query, err := core.ParseEncodedURI(raw)
|
|
if err != nil {
|
|
client.LogError("Invalid request: %s", raw)
|
|
handleError(client, err)
|
|
return
|
|
}
|
|
|
|
// If prefixed by 'URL:' send a redirect
|
|
if strings.HasPrefix(path, "/URL:") {
|
|
raw = raw[5:]
|
|
client.Conn().Write(generateHTMLRedirect(raw))
|
|
client.LogInfo("Redirect to: %s", raw)
|
|
return
|
|
}
|
|
|
|
// Create new request and add the extra query part
|
|
request := core.NewRequest(core.BuildPath(path), query)
|
|
request.AddToQuery(extra)
|
|
|
|
// Handle the request!
|
|
err = core.HandleClient(client, request)
|
|
|
|
// Final error handling
|
|
if err != nil {
|
|
handleError(client, err)
|
|
client.LogError("Failed to serve: %s", request.String())
|
|
} else {
|
|
client.LogInfo("Served: %s", request.String())
|
|
}
|
|
}
|
|
|
|
func handleDirectory(client *core.Client, file *os.File, p *core.Path) error {
|
|
// First check for gophermap, create gophermap Path object
|
|
gophermap := p.JoinPathUnsafe("gophermap")
|
|
|
|
// If gophermap exists, we fetch this
|
|
file2, err := core.OpenFile(gophermap)
|
|
if err == nil {
|
|
stat, osErr := file2.Stat()
|
|
if osErr == nil {
|
|
// Fetch gophermap and defer close
|
|
defer file2.Close()
|
|
return core.FetchFile(client, file2, stat, gophermap)
|
|
}
|
|
|
|
// Else, just close file2
|
|
file2.Close()
|
|
}
|
|
|
|
// Slice to write
|
|
dirContents := make([]byte, 0)
|
|
|
|
// Add directory heading, empty line and a back line
|
|
dirContents = append(dirContents, buildLine(typeInfo, "[ "+core.Hostname+p.Selector()+" ]", "TITLE", nullHost, nullPort)...)
|
|
dirContents = append(dirContents, buildInfoLine("")...)
|
|
dirContents = append(dirContents, buildLine(typeDirectory, "..", p.Selector(), core.Hostname, core.Port)...)
|
|
|
|
// Scan directory and build lines
|
|
err = core.ScanDirectory(
|
|
file,
|
|
p,
|
|
func(file os.FileInfo, fp *core.Path) {
|
|
// Append new formatted file listing (if correct type)
|
|
dirContents = appendFileListing(dirContents, file, fp)
|
|
},
|
|
)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
// Add footer, write contents
|
|
dirContents = append(dirContents, footer...)
|
|
return client.Conn().Write(dirContents)
|
|
}
|
|
|
|
func handleLargeFile(client *core.Client, file *os.File, p *core.Path) error {
|
|
return client.Conn().ReadFrom(file)
|
|
}
|
|
|
|
// handleError determines whether to send an error response to the client, and logs to system
|
|
func handleError(client *core.Client, err error) {
|
|
response, ok := generateErrorResponse(err)
|
|
if ok {
|
|
client.Conn().Write(response)
|
|
}
|
|
core.SystemLog.Errorf(err.Error())
|
|
}
|
|
|
|
// newFileContents returns a new FileContents object
|
|
func newFileContent(p *core.Path) core.FileContent {
|
|
if isGophermap(p) {
|
|
return &gophermapContent{}
|
|
}
|
|
return &core.RegularFileContent{}
|
|
}
|