Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Added new files... D'oh

  • Loading branch information...
commit 42174a58597bf75ec8218b9c57b2f0e6382aaae9 1 parent 1356809
@micrypt authored
Showing with 390 additions and 0 deletions.
  1. +356 −0 fluidinfo.go
  2. +34 −0 fluidinfo_test.go
View
356 fluidinfo.go
@@ -0,0 +1,356 @@
+/*
+Copyright (c) 2010 Seyi Ogunyemi
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+*/
+
+package fluidinfo
+
+import (
+ "http"
+ "encoding/base64"
+ "io"
+ "os"
+ "strings"
+ "net"
+ "bufio"
+ "strconv"
+ "fmt"
+ "bytes"
+ "container/vector"
+ "url"
+)
+
+type readClose struct {
+ io.Reader
+ io.Closer
+}
+
+type badStringError struct {
+ what string
+ str string
+}
+
+func (e *badStringError) String() string { return fmt.Sprintf("%s %q", e.what, e.str) }
+
+// Given a string of the form "host", "host:port", or "[ipv6::address]:port",
+// return true if the string includes a port.
+func hasPort(s string) bool { return strings.LastIndex(s, ":") > strings.LastIndex(s, "]") }
+
+func send(req *http.Request) (resp *http.Response, err os.Error) {
+ addr := req.URL.Host
+ if !hasPort(addr) {
+ addr += ":http"
+ }
+ conn, err := net.Dial("tcp", addr)
+ if err != nil {
+ return nil, err
+ }
+ err = req.Write(conn)
+ if err != nil {
+ conn.Close()
+ return nil, err
+ }
+ reader := bufio.NewReader(conn)
+ resp, err = http.ReadResponse(reader, req)
+ if err != nil {
+ conn.Close()
+ return nil, err
+ }
+ r := io.Reader(reader)
+ if v := resp.Header["Content-Length"]; v != nil {
+ n, err := strconv.Atoi64(v[0])
+ if err != nil {
+ return nil, &badStringError{"invalid Content-Length", v[0]}
+ }
+ r = io.LimitReader(r, n)
+ }
+ resp.Body = readClose{r, conn}
+ return
+}
+
+func encodedUsernameAndPassword(user, pwd string) string {
+ bb := &bytes.Buffer{}
+ encoder := base64.NewEncoder(base64.StdEncoding, bb)
+ encoder.Write([]byte(user + ":" + pwd))
+ encoder.Close()
+ return bb.String()
+}
+
+// Naive utility url encode method. Converts a string map into a query string
+//
+// Returns a string in the format "?param1=value1&param2=value2"
+func UrlEncode(urlmap map[string]string) string {
+ url_ := "?"
+ var temp vector.StringVector
+ var key, value string
+ for key, value = range urlmap {
+ temp.Push(key + "=" + value)
+ }
+ url_ += strings.Join(temp, "&")
+ return url_
+}
+
+func authGet(url_, user, pwd string) (r *http.Response, err os.Error) {
+ var req http.Request
+ req.Method = "GET"
+ req.Header = map[string][]string{"Authorization": {"Basic " +
+ encodedUsernameAndPassword(user, pwd)}}
+ if req.URL, err = url.Parse(url_); err != nil {
+ return
+ }
+ if r, err = send(&req); err != nil {
+ return
+ }
+ return
+}
+
+// Post issues a POST to the specified URL.
+//
+// Caller should close r.Body when done reading it.
+func authPost(url_, user, pwd, client, clientURL, version, agent, bodyType string,
+body io.Reader) (r *http.Response, err os.Error) {
+ var req http.Request
+ req.Method = "POST"
+ req.Body = body.(io.ReadCloser)
+ req.Header = map[string][]string{
+ "Content-Type": {bodyType},
+ "Transfer-Encoding": {"chunked"},
+ "User-Agent": {agent},
+ "X-Fluidinfo-Client": {client},
+ "X-Fluidinfo-Client-URL": {clientURL},
+ "X-Fluidinfo-Version": {version},
+ "Authorization": {"Basic " + encodedUsernameAndPassword(user, pwd)},
+ }
+
+ req.URL, err = url.Parse(url_)
+ if err != nil {
+ return nil, err
+ }
+
+ return send(&req)
+}
+
+// Put issues a PUT to the specified URL.
+//
+// Caller should close r.Body when done reading it.
+func authPut(url_, user, pwd, client, clientURL, version, agent, bodyType string,
+body io.Reader) (r *http.Response, err os.Error) {
+ var req http.Request
+ req.Method = "PUT"
+ req.Body = body.(io.ReadCloser)
+ if user != "" && pwd != "" {
+ req.Header = map[string][]string{
+ "Content-Type": {bodyType},
+ "Transfer-Encoding": {"chunked"},
+ "User-Agent": {agent},
+ "X-Fluidinfo-Client": {client},
+ "X-Fluidinfo-Client-URL": {clientURL},
+ "X-Fluidinfo-Version": {version},
+ "Authorization": {"Basic " + encodedUsernameAndPassword(user, pwd)},
+ }
+ } else {
+ req.Header = map[string][]string{
+ "Content-Type": {bodyType},
+ "Transfer-Encoding": {"chunked"},
+ "User-Agent": {agent},
+ "X-Fluidinfo-Client": {client},
+ "X-Fluidinfo-Client-URL": {clientURL},
+ "X-Fluidinfo-Version": {version},
+ }
+ }
+
+ req.URL, err = url.Parse(url_)
+ if err != nil {
+ return nil, err
+ }
+
+ return send(&req)
+}
+
+// Delete issues a DELETE to the specified URL.
+func authDelete(url_, user, pwd string) (r *http.Response, err os.Error) {
+ var req http.Request
+ req.Method = "DELETE"
+ if user != "" && pwd != "" {
+ req.Header = map[string][]string{"Authorization": {"Basic " +
+ encodedUsernameAndPassword(user, pwd)}}
+ }
+ if req.URL, err = url.Parse(url_); err != nil {
+ return
+ }
+ if r, err = send(&req); err != nil {
+ return
+ }
+ return
+}
+
+// Head issues a HEAD to the specified URL.
+func authHead(url_, user, pwd string) (r *http.Response, err os.Error) {
+ var req http.Request
+ req.Method = "HEAD"
+ if user != "" && pwd != "" {
+ req.Header = map[string][]string{"Authorization": {"Basic " +
+ encodedUsernameAndPassword(user, pwd)}}
+ }
+ if req.URL, err = url.Parse(url_); err != nil {
+ return
+ }
+ if r, err = send(&req); err != nil {
+ return
+ }
+ return
+}
+
+// Do an authenticated Get if we've called Authenticated, otherwise
+// just Get it without authentication
+func httpGet(url_, user, pwd string) (*http.Response, string, os.Error) {
+ var r *http.Response
+ var full string = ""
+ var err os.Error
+ if user != "" && pwd != "" {
+ r, err = authGet(url_, user, pwd)
+ } else {
+ r, err = http.Get(url_)
+ }
+ return r, full, err
+}
+
+// Do an authenticated Post if we've called Authenticated, otherwise
+// just Post it without authentication
+func httpPost(url_, user, pwd, client, clientURL, version, agent,
+data string) (*http.Response, os.Error) {
+ var r *http.Response
+ var err os.Error
+ body := bytes.NewBufferString(data)
+ bodyType := "application/json"
+ if user != "" && pwd != "" {
+ r, err = authPost(url_, user, pwd, client, clientURL,
+ version, agent, bodyType, body)
+ } else {
+ r, err = http.Post(url_, bodyType, body)
+ }
+ return r, err
+}
+
+// Do an authenticated Put
+func httpPut(url_, user, pwd, client, clientURL, version, agent,
+data string) (*http.Response, os.Error) {
+ var r *http.Response
+ var err os.Error
+ body := bytes.NewBufferString(data)
+ bodyType := "application/json"
+ r, err = authPut(url_, user, pwd, client, clientURL,
+ version, agent, bodyType, body)
+ return r, err
+}
+
+// Do an authenticated Delete
+func httpDelete(url_, user, pwd string) (*http.Response, os.Error) {
+ var r *http.Response
+ var err os.Error
+ r, err = authDelete(url_, user, pwd)
+ return r, err
+}
+
+// Do an authenticated Head
+func httpHead(url_, user, pwd string) (*http.Response, os.Error) {
+ var r *http.Response
+ var err os.Error
+ r, err = authHead(url_, user, pwd)
+ return r, err
+}
+
+const (
+ DEFAULT_CLIENT = "gofluidinfo"
+ DEFAULT_CLIENT_URL = "http://github.com/micrypt/gofluidinfo"
+ DEFAULT_CLIENT_VERSION = "0.1"
+ DEFAULT_USER_AGENT = "gofluidinfo"
+ ERROR = "gofluidinfo Error: "
+ WARNING = "gofluidinfo Warning: "
+ DEFAULT_PORT = 80
+ SECURE_PORT = 443
+ UNIX_CREDENTIALS_FILE = ".fluidinfocredentials"
+ // Here's hoping there's a stable Go port to the Windows platform sometime in the future.
+ // WINDOWS_CREDENTIALS_FILE = "fluidinfocredentials.ini"
+ RETRY_TIMEOUT = 5e9 // unlikely the user will choose this
+ PRIMITIVE_CONTENT_TYPE = "application/vnd.fluidinfo.value+json"
+ HEADER_ERROR = "X-Fluidinfo-Error-Class"
+ HEADER_REQUEST_ID = "X-Fluidinfo-Request-Id"
+ FLUIDINFO_PATH = "http://fluiddb.fluidinfo.com"
+ SANDBOX_PATH = "http://sandbox.fluidinfo.com"
+)
+
+type Client struct {
+ Username string
+ Password string
+ URL string
+ Client string
+ ClientURL string
+ Version string
+ Agent string
+}
+
+func NewClient(username, password string) *Client {
+ return &Client{username, password, SANDBOX_PATH, DEFAULT_CLIENT, DEFAULT_CLIENT_URL, DEFAULT_CLIENT_VERSION, DEFAULT_USER_AGENT}
+}
+
+func (self *Client) SetActiveMode() {
+ self.URL = FLUIDINFO_PATH
+}
+
+func (self *Client) Get(url_ string) (*http.Response, os.Error) {
+ url_ = self.URL + url_
+ var resp *http.Response
+ var err os.Error
+ resp, _, err = httpGet(url_, self.Username, self.Password)
+ return resp, err
+}
+
+func (self *Client) Post(url_, data string) (*http.Response, os.Error) {
+ url_ = self.URL + url_
+ var resp *http.Response
+ var err os.Error
+ resp, err = httpPost(url_, self.Username, self.Password, self.Client, self.ClientURL, self.Version, self.Agent, data)
+ return resp, err
+}
+
+func (self *Client) Put(url_, data string) (*http.Response, os.Error) {
+ url_ = self.URL + url_
+ var resp *http.Response
+ var err os.Error
+ resp, err = httpPut(url_, self.Username, self.Password, self.Client, self.ClientURL, self.Version, self.Agent, data)
+ return resp, err
+}
+
+func (self *Client) Delete(url_ string) (*http.Response, os.Error) {
+ url_ = self.URL + url_
+ var resp *http.Response
+ var err os.Error
+ resp, err = httpDelete(url_, self.Username, self.Password)
+ return resp, err
+}
+
+func (self *Client) Head(url_ string) (*http.Response, os.Error) {
+ url_ = self.URL + url_
+ var resp *http.Response
+ var err os.Error
+ resp, err = httpHead(url_, self.Username, self.Password)
+ return resp, err
+}
View
34 fluidinfo_test.go
@@ -0,0 +1,34 @@
+//Example call using the fluidinfo package
+
+package main
+
+import (
+"fmt"
+"io/ioutil"
+"log"
+"./fluidinfo"
+)
+
+func main() {
+
+ // Call to url pattern "/users/username"
+ url := "/users/test"
+
+ myclient := fluidinfo.NewClient("test","test")
+
+ r, err := myclient.Get(url)
+
+ var b []byte
+ if err == nil {
+ b, err = ioutil.ReadAll(r.Body)
+ r.Body.Close()
+ }
+
+ if err != nil {
+ log.Fatal(err)
+ } else {
+ fmt.Println(string(b))
+ }
+
+}
+
Please sign in to comment.
Something went wrong with that request. Please try again.