From b7513a86fa45c6fcc09652191a91a57d146a0d1b Mon Sep 17 00:00:00 2001 From: Ken Sternberg Date: Tue, 9 Jan 2018 15:41:51 -0800 Subject: [PATCH] Initial commit -- RFC1288 parser is passing unit tests. --- .gitignore | 10 ++++ README.md | 32 ++++++++++ monologued/main.go | 7 +++ rfc1288/rfc1288.go | 90 ++++++++++++++++++++++++++++ rfc1288/rfc1288_test.go | 126 ++++++++++++++++++++++++++++++++++++++++ 5 files changed, 265 insertions(+) create mode 100644 README.md create mode 100644 monologued/main.go create mode 100644 rfc1288/rfc1288.go create mode 100644 rfc1288/rfc1288_test.go diff --git a/.gitignore b/.gitignore index a1338d6..b5ab711 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,13 @@ +*# +.#* +*~ +*.orig +*.aux +*.log +*.out +*.pdf +*.bk + # Binaries for programs and plugins *.exe *.dll diff --git a/README.md b/README.md new file mode 100644 index 0000000..b3e0571 --- /dev/null +++ b/README.md @@ -0,0 +1,32 @@ +# MONOLOGUED + +Monologued is an implementation of an +[RFC1288](https://tools.ietf.org/html/rfc1288) protocol server in Go. + +That's right. Monologued is a +*[Finger](https://en.wikipedia.org/wiki/Finger_protocol)* server. + +# WHY‽‽‽‽ + +While what I really wanted was to +[learn Rust](https://github.com/elfsternberg/monologued), work decided that +Go was a better choice. Since I have to learn it, this seemed like the +best way to go about it. Still not thrilled with the decision, but maybe +I'll get a blog post out of it. + +# Status + +Monologued is still very much not working. Don't even bother +downloading. It's mostly something to cut my teeth on while I try to +figure out how Go works. + +# Thanks + +Thanks to my friend Nathaniel for the answer to my original question, +"In a movie, when the villain is explaining his plans at length, what is +that called?" Nathaniel explained that "He's monologuing," and now you +know why it has that name. + +# License + +Apache 2.0. See the accompanying LICENSE file in this directory. diff --git a/monologued/main.go b/monologued/main.go new file mode 100644 index 0000000..d9685e6 --- /dev/null +++ b/monologued/main.go @@ -0,0 +1,7 @@ +package main + +import "fmt" + +func main() { + fmt.Println("What the fuck, over?", extraNonsense()) +} diff --git a/rfc1288/rfc1288.go b/rfc1288/rfc1288.go new file mode 100644 index 0000000..b548271 --- /dev/null +++ b/rfc1288/rfc1288.go @@ -0,0 +1,90 @@ +package rfc1288 + +import( + "bytes" +// "fmt" +) + +func is_unix_conventional(c byte) bool { + return (c >= '0' && c <= '9') || (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') +} + +var Rfc1288ErrorMsgs = []string { + "", + "Protocol prefix not recognized", + "Protocol request does not meet specifications", +} + +type Rfc1288ErrorCode int + +const ( + Ok Rfc1288ErrorCode = 0 + BadProtocol Rfc1288ErrorCode = 1 + BadRequest Rfc1288ErrorCode = 2 +) + +type Rfc1288RequestType int + +const ( + UserList Rfc1288RequestType = 0 + User Rfc1288RequestType = 1 + Remote Rfc1288RequestType = 2 +) + +type Rfc1288Request struct { + Type Rfc1288RequestType + User* string + Host* string +} + +func parse_rfc1288_request(Buffer string) (Rfc1288ErrorCode, *Rfc1288Request) { + Buflen := len(Buffer) + + if Buflen < 2 { + return BadProtocol, nil + } + + if Buffer[0] != '/' || (Buffer[1] != 'W' && Buffer[1] != 'w') { + return BadProtocol, nil + } + + if len(Buffer) == 2 { + return Ok, &Rfc1288Request{UserList, nil, nil} + } + + index := 2 + for index < Buflen && Buffer[index] == ' ' { + index += 1 + } + + if Buflen == index { + return Ok, &Rfc1288Request{Type: UserList, User: nil, Host: nil} + } + + user := bytes.NewBufferString("") + host := bytes.NewBufferString("") + + for index < Buflen && is_unix_conventional(Buffer[index]) { + user.WriteByte(Buffer[index]) + index += 1 + } + + if index == Buflen || (index < Buflen && Buffer[index] == ' ') { + ruser := user.String() + return Ok, &Rfc1288Request{Type: User, User: &ruser, Host: nil} + } + + if Buffer[index] != '@' { + return BadRequest, nil + } + + index += 1 + for index < Buflen && Buffer[index] != ' ' { + host.WriteByte(Buffer[index]) + index += 1 + } + + ruser := user.String() + rhost := host.String() + return Ok, &Rfc1288Request{Type: Remote, User: &ruser, Host: &rhost} +} diff --git a/rfc1288/rfc1288_test.go b/rfc1288/rfc1288_test.go new file mode 100644 index 0000000..12af656 --- /dev/null +++ b/rfc1288/rfc1288_test.go @@ -0,0 +1,126 @@ +package rfc1288 + +import "testing" + +func TestGood_List(t *testing.T) { + res, req := parse_rfc1288_request("/W") + if res != Ok { + t.Error("Expected a good return") + } + if req.Type != UserList { + t.Error("Expected UserList as a return type") + } +} + +func TestGood_ListWSpaces(t *testing.T) { + res, req := parse_rfc1288_request("/W "); + if res != Ok { + t.Error("Expected a good return") + } + if req.Type != UserList { + t.Error("Expected UserList as a return type") + } +} + +func TestBad_Start(t *testing.T) { + res, _ := parse_rfc1288_request("") + if res != BadProtocol { + t.Error("Expected BadProtocol") + } +} + +func TestBad_Start1(t *testing.T) { + res, _ := parse_rfc1288_request("/") + if res != BadProtocol { + t.Error("Expected BadProtocol") + } +} + +func TestBad_Start2(t *testing.T) { + res, _ := parse_rfc1288_request("/X") + if res != BadProtocol { + t.Error("Expected BadProtocol, got", res) + } +} + +func TestGood_Name(t *testing.T) { + res, req := parse_rfc1288_request("/W foozle") + if res != Ok { + t.Error("Expected a good return") + } + if req.Type != User { + t.Error("Expected User as a return type") + } + if *req.User != "foozle" { + t.Error("The user name did not match passed in value.") + } +} + +func TestGood_NameExtraSpace(t *testing.T) { + res, req := parse_rfc1288_request("/W foozle ") + if res != Ok { + t.Error("Expected a good return") + } + if req.Type != User { + t.Error("Expected User as a return type") + } + if *req.User != "foozle" { + t.Error("The user name did not match passed in value.") + } +} + +func TestGood_NameWHost(t *testing.T) { + res, req := parse_rfc1288_request("/W foozle@localhost") + if res != Ok { + t.Error("Expected a good return") + } + if req.Type != Remote { + t.Error("Expected Remote as a return type") + } + if *req.User != "foozle" { + t.Error("The user name did not match passed in value.") + } + if *req.Host != "localhost" { + t.Error("The host name did not match passed in value.") + } +} + +func TestGood_NameWHostAndSpaces(t *testing.T) { + res, req := parse_rfc1288_request("/W foozle@localhost ") + if res != Ok { + t.Error("Expected a good return") + } + if req.Type != Remote { + t.Error("Expected Remote as a return type") + } + if *req.User != "foozle" { + t.Error("The user name did not match passed in value.") + } + if *req.Host != "localhost" { + t.Error("The host name did not match passed in value.") + } +} + +func TestGood_NameWHostAndSpacesAndLowerW(t *testing.T) { + res, req := parse_rfc1288_request("/w foozle@localhost ") + if res != Ok { + t.Error("Expected a good return") + } + if req.Type != Remote { + t.Error("Expected Remote as a return type") + } + if *req.User != "foozle" { + t.Error("The user name did not match passed in value.") + } + if *req.Host != "localhost" { + t.Error("The host name did not match passed in value.") + } +} + +func TestBad_Name(t *testing.T) { + res, _ := parse_rfc1288_request("/W foozle.. ") + if res != BadRequest { + t.Error("Expected BadRequest") + } +} +