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.
gophi/gopher/server.go

125 lines
3.0 KiB
Go

package gopher
import (
"gophi/core"
"os"
"strings"
)
// 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(clientReadFailStr)
handleError(client, err)
return
}
// Convert to string + remove leading '/'
line := strings.TrimPrefix(string(received), "/")
// If prefixed by 'URL:' send a redirect
lenBefore := len(line)
line = strings.TrimPrefix(line, "URL:")
if len(line) < lenBefore {
client.Conn().Write(generateHTMLRedirect(line))
client.LogInfo(clientRedirectFmtStr, line)
return
}
// Parse new request
request, err := core.ParseURLEncodedRequest(line)
if err != nil {
client.LogError(clientRequestParseFailStr)
handleError(client, err)
return
}
// Handle the request!
err = core.FileSystem.HandleClient(
// Current client
client,
// Current request
request,
// New file contents function
newFileContents,
// Handle directory function
func(fs *core.FileSystemObject, client *core.Client, fd *os.File, p *core.Path) core.Error {
// First check for gophermap, create gophermap Path object
gophermap := p.JoinPath("gophermap")
// If gophermap exists, we fetch this
fd2, err := fs.OpenFile(gophermap)
if err == nil {
stat, osErr := fd2.Stat()
if osErr == nil {
// Fetch gophermap and defer close
defer fd2.Close()
return fs.FetchFile(client, fd2, stat, gophermap, newFileContents)
}
// Else, just close fd2
fd2.Close()
}
// Slice to write
dirContents := make([]byte, 0)
// Add directory heading + empty line
dirContents = append(dirContents, buildLine(typeInfo, "[ "+core.Hostname+p.Selector()+" ]", "TITLE", nullHost, nullPort)...)
dirContents = append(dirContents, buildInfoLine("")...)
// Scan directory and build lines
err = fs.ScanDirectory(
// Directory fd
fd,
// Directory path
p,
// Iter function
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)
},
)
// Final error handling
if err != nil {
handleError(client, err)
client.LogError(clientServeFailStr, request.Path().Absolute())
} else {
client.LogInfo(clientServedStr, request.Path().Absolute())
}
}
// handleError determines whether to send an error response to the client, and logs to system
func handleError(client *core.Client, err core.Error) {
response, ok := generateErrorResponse(err.Code())
if ok {
client.Conn().Write(response)
}
core.SystemLog.Error(err.Error())
}
// newFileContents returns a new FileContents object
func newFileContents(p *core.Path) core.FileContents {
if isGophermap(p) {
return &gophermapContents{}
}
return &core.RegularFileContents{}
}