Char | Type |
---|---|
0 | Text file |
1 | Gopher submenu |
2 | CCSO Nameserver |
3 | Error code returned by a Gopher server to indicate failure |
4 | BinHex-encoded file (primarily for Macintosh computers) |
5 | DOS file |
6 | uuencoded file |
7 | Gopher full-text search |
8 | Telnet |
9 | Binary file |
+ | Mirror or alternate server |
g | GIF file |
I | Image file |
T | Telnet 3270 |
Protocol Junkie: Gopher
Published on September 2, 2022 protocol-junkie protocol gopherGopher is a communication protocol designed for distributing, searching, and retrieving documents in Internet Protocol networks that was invented by Mark P. McCahill at the University of Minnesota in 1991.
People that think that the web is bloated, often bring up gopher when talking about ways of fixing the internet. Their way of fixing the bloatness of the web is by limiting what you can do with it; and I’m all for a bloatless web, but not by limiting what people can do with it.
One more thing to think about: You wouldn’t even hear about the people that are actually advocating for this, because they would all be hidden in their so called “gopher holes”.
One thing that I must admit, is the fact that gopher is suitable for large online encyclopedias or other systems that store lots of information. I don’t think that there currently is something more suitable for such a task. Gopher’s hierarhical way of serving data is just perfect for that kind of stuff.
The protocol
The gopher protocol is so simple, the server doesn’t even need to handle any kinda of state; it almost feels wrong calling it a protocol. Imagine that: a small, efficient and state-less protocol that can deliever the same kind of content as a 20 MB news page.
In essence, the Gopher protocol consists of a client connecting to a server and sending the server a selector (a line of text, which may be empty) via a TCP connection. The server responds with a block of text terminated with a period on a line by itself, and closes the connection. No state is retained by the server between transactions with a client. The simple nature of the protocol stems from the need to implement servers and clients for the slow, smaller desktop computers (1 MB Macs and DOS machines), quickly, and efficiently.
I think that quote summarizes almost everything. I’m just gonna list some code snippets that implement what it says.
package main
import (
"fmt"
"io/ioutil"
"net"
"strings"
"time"
)
var (
crlf = "\r\n"
timeout = 15 * time.Second
)
func Retrieve(host, port, resource string) ([]byte, error) {
nullResp := make([]byte, 0)
addr := host + ":" + port
// Opens TCP connection
conn, err := net.DialTimeout("tcp", addr, timeout)
if err != nil {
return nullResp, err
}
// Sends an empty line: Meaning "list what you have")
_, err = conn.Write([]byte(resource + crlf))
if err != nil {
return nullResp, err
}
// Read server's response
result, err := ioutil.ReadAll(conn)
if err != nil {
return nullResp, err
}
return result, err
}
func main() {
res, _ := Retrieve("gopher.floodmap.com", "70", "/")
fmt.Println(res)
}
The RFC also shows this nice example interaction between a client and a server.
Client: {Opens connection to rawBits.micro.umn.edu at port 70}
Server: {Accepts connection but says nothing}
Client: <CR><LF> {Sends an empty line: Meaning "list what you have"}
Server: {Sends a series of lines, each ending with CR LF}
0About internet GopherFStuff:About usFrawBits.micro.umn.eduF70
1Around University of MinnesotaFZ,5692,AUMFunderdog.micro.umn.eduF70
1Microcomputer News & PricesFPrices/Fpserver.bookstore.umn.eduF70
1Courses, Schedules, CalendarsFFevents.ais.umn.eduF9120
1Student-Staff DirectoriesFFuinfo.ais.umn.eduF70
1Departmental PublicationsFStuff:DP:FrawBits.micro.umn.eduF70
{.....etc.....}
. {Period on a line by itself}
{Server closes connection}
Parsing the response
Because the response is plain text, we need to loop over each line. The line’s first character represents the item type and the rest of the line represents it’s value + some tab-separated “arguments”.
Char | Type |
---|---|
d | Doc. Seen used alongside PDF’s and .DOC’s |
h | HTML file |
i | Informational message, widely used.[24] |
j | image file “(especially the jpg format)” |
p | image file “(especially the png format)” |
r | document rtf file “rich text Format”) |
s | Sound file (especially the WAV format) |
w | document wri file “write of microsoft Format”) |
P | document pdf file “Portable Document Format”) |
X | document xml file “eXtensive Markup Language” ) |
package main
// func Recieve(...) ... {
// ...
// }
func main() {
res, _ := Retrieve("gopher.floodmap.com", "70", "/")
lines := string.Split(string(res), crlf)
for _, l := range lines {
if l[0] == '0' {
// file
} else if l[0] == '1' {
// directory
} // and so on ...
}
}
Search transactions
The search transaction allows you to search through the content that a server provides, but because gopher is so simple and extensible, I can really see other ways to use this.
C: Opens Connection.
C: Sends Selector String, Tab, Search String.
S: Sends Menu Entity.
Conclusion
At first, I considered gopher an old, outdates and limited
protocol that has no use in the modern internet; and part of that
might be true, but I can really see this protocol being useful for
wikis or encyclopedias.
I still don’t think that gopher is the solution to the bloatness of
the web, but I must admit that gopher is really extensible and it
could be put to work in some parts of the internet.