529d28e62e
Signed-off-by: kim (grufwub) <grufwub@gmail.com>
125 lines
3.0 KiB
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{}
|
|
}
|