Browse Source

some improvments in the API

master
Brett Langdon 10 years ago
parent
commit
b376abb386
5 changed files with 73 additions and 25 deletions
  1. +6
    -0
      Makefile
  2. +4
    -0
      cmd/terse/terse.go
  3. +23
    -5
      server.go
  4. +0
    -20
      url.go
  5. +40
    -0
      util.go

+ 6
- 0
Makefile View File

@ -1,5 +1,11 @@
terse: ./url.go ./server.go ./cmd/terse/terse.go
go build ./cmd/terse
run:
go run ./cmd/terse/terse.go
clean:
rm -f ./terse
.PHONY: run clean

+ 4
- 0
cmd/terse/terse.go View File

@ -13,10 +13,14 @@ var args struct {
}
func main() {
// Setup default args
args.MaxEntries = 1000
args.Bind = "127.0.0.1:5892"
// Parse args from CLI
arg.MustParse(&args)
// Start the server
server := terse.NewServer(args.Bind, args.MaxEntries)
log.Fatal(server.ListenAndServe())
}

+ 23
- 5
server.go View File

@ -27,8 +27,12 @@ func (handler *Handler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
func (handler *Handler) HandleGet(w http.ResponseWriter, r *http.Request) {
url := strings.Trim(r.URL.Path, "/")
// If they gave us something like `/<shortcode>/<who knows>`
// then jst grab the first part
code := strings.SplitN(url, "/", 2)[0]
value, ok := handler.cache.Get(code)
// If the url exists in the cache and is a string, redirect to it
if ok {
switch url := value.(type) {
case string:
@ -40,15 +44,29 @@ func (handler *Handler) HandleGet(w http.ResponseWriter, r *http.Request) {
}
func (handler *Handler) HandlePost(w http.ResponseWriter, r *http.Request) {
// Parse url from body
reader := bufio.NewScanner(r.Body)
reader.Scan()
url, err := url.ParseRequestURI(reader.Text())
rawurl := reader.Text()
// Ensure url given is a real url
cleanUrl, err := CleanURL(rawurl)
if err != nil {
panic(err)
http.Error(w, fmt.Sprintf("Invalid url \"%s\"", reader.Text()), http.StatusBadRequest)
return
}
// Generate short code and store in cache
code := GetShortCode([]byte(cleanUrl))
handler.cache.Add(code, cleanUrl)
// Generate response url
codeUrl := &url.URL{
Scheme: "https",
Host: r.Host,
Path: "/" + code,
}
code := GetShortCode([]byte(url.String()))
handler.cache.Add(code, url.String())
fmt.Fprintf(w, code)
fmt.Fprintf(w, codeUrl.String())
}
func NewServer(bind string, maxEntries int) *http.Server {


+ 0
- 20
url.go View File

@ -1,20 +0,0 @@
package terse
import (
"bytes"
"hash/crc32"
)
const ALPHABET string = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-._~"
const BASE uint32 = uint32(len(ALPHABET))
func GetShortCode(url []byte) string {
var code bytes.Buffer
num := crc32.ChecksumIEEE(url)
for num > 0 {
next := (num % BASE)
code.WriteRune(rune(ALPHABET[next]))
num = num / 62
}
return code.String()
}

+ 40
- 0
util.go View File

@ -0,0 +1,40 @@
package terse
import (
"bytes"
"fmt"
"hash/crc32"
"net/url"
)
// URL safe characters, as definied by section 2.3 of RFC 3986 (http://www.ietf.org/rfc/rfc3986.txt)
const ALPHABET string = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-._~"
const BASE uint32 = uint32(len(ALPHABET))
func GetShortCode(url []byte) string {
var code bytes.Buffer
num := crc32.ChecksumIEEE(url)
for num > 0 {
next := (num % BASE)
code.WriteRune(rune(ALPHABET[next]))
num = num / 62
}
return code.String()
}
func CleanURL(rawurl string) (string, error) {
parsed, err := url.ParseRequestURI(rawurl)
if err != nil {
return "", fmt.Errorf("Error parsing url \"%s\": %s", rawurl, err)
}
if parsed.Scheme != "http" && parsed.Scheme != "https" {
return "", fmt.Errorf("Scheme \"%s\" not allowed for url \"%s\"", parsed.Scheme, rawurl)
}
if parsed.Host == "" {
return "", fmt.Errorf("No hostname provided for url \"%s\"", rawurl)
}
return parsed.String(), nil
}

Loading…
Cancel
Save