summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.gitignore1
-rw-r--r--cnpreq.go132
2 files changed, 133 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..b0e0b57
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1 @@
+/cnp-req
diff --git a/cnpreq.go b/cnpreq.go
new file mode 100644
index 0000000..f0efb7c
--- /dev/null
+++ b/cnpreq.go
@@ -0,0 +1,132 @@
+package main
+
+import (
+ "bytes"
+ "flag"
+ "fmt"
+ "io"
+ "os"
+ "path"
+ "strings"
+
+ "contnet.org/lib/cnp-go"
+)
+
+var prog = path.Base(os.Args[0])
+
+func checkerr(err error) {
+ if err != nil {
+ fmt.Fprintf(os.Stderr, "%s: error: %s\n", prog, err)
+ os.Exit(1)
+ }
+}
+
+type requestPrinter struct {
+ out io.Writer
+ body io.Reader
+ n int64
+ notFirst bool
+}
+
+func (p *requestPrinter) Read(b []byte) (int, error) {
+ n, err := p.body.Read(b)
+ p.n += int64(n)
+ if n > 0 && !p.notFirst {
+ p.out.Write([]byte("> "))
+ p.notFirst = true
+ }
+ p.out.Write(bytes.Replace(b[:n], []byte("\n"), []byte("\n> "), -1))
+ if err == io.EOF && p.n > 0 {
+ p.out.Write([]byte("\n"))
+ }
+ return n, err
+}
+
+func send(r *cnp.Request, printReq, printHdr, printBody bool) {
+ if printReq {
+ if r.Body != nil {
+ if _, ok := r.Header.Parameters["length"]; !ok {
+ r.ComputeLength()
+ }
+
+ fmt.Fprint(os.Stderr, "> ")
+ r.Header.Write(os.Stderr)
+ r.Body = &requestPrinter{out: os.Stderr, body: io.LimitReader(r.Body, r.Length())}
+ } else {
+ fmt.Fprint(os.Stderr, "> ")
+ r.Header.Write(os.Stderr)
+ }
+ }
+
+ resp, err := cnp.Send(r)
+ checkerr(err)
+ defer resp.Close()
+
+ if printHdr {
+ checkerr(resp.Header.Write(os.Stdout))
+ }
+
+ if printBody {
+ l := resp.Length()
+ if l > 0 {
+ resp.Body = io.LimitReader(resp.Body, l)
+ }
+ _, err = io.Copy(os.Stdout, resp.Body)
+ checkerr(err)
+ }
+}
+
+func usage(f io.Writer) {
+ fmt.Fprintf(f, "%s: usage: %s {URL|HOST/PATH} [PARAM=VALUE ...]\n", prog, prog)
+}
+
+func main() {
+ printReq := flag.Bool("v", false, "print the request header and body")
+ printHdr := flag.Bool("i", false, "print the response header")
+ noBody := flag.Bool("I", false, "only print the response header without the body")
+ rawParams := flag.Bool("r", false, "treat parameters as raw CNP-encoded parameters")
+ readBody := flag.Bool("b", false, "read body data from stdin")
+ body := flag.String("B", "", "body data")
+
+ flag.Parse()
+
+ if flag.NArg() < 1 {
+ usage(os.Stderr)
+ os.Exit(2)
+ }
+
+ var req *cnp.Request
+ var err error
+ if strings.HasPrefix(flag.Arg(0), "cnp:") || strings.HasPrefix(flag.Arg(0), "/") {
+ req, err = cnp.NewRequestURL(flag.Arg(0), nil)
+ } else {
+ ss := strings.SplitN(flag.Arg(0), "/", 2)
+ if len(ss) != 2 {
+ usage(os.Stderr)
+ os.Exit(2)
+ }
+ req, err = cnp.NewRequest(ss[0], "/"+ss[1], nil)
+ }
+ checkerr(err)
+
+ req.Body = strings.NewReader(*body)
+ if *readBody {
+ req.Body = os.Stdin
+ }
+
+ for _, arg := range flag.Args()[1:] {
+ ss := strings.SplitN(arg, "=", 2)
+ if len(ss) != 2 {
+ checkerr(fmt.Errorf("invalid parameter: %q", arg))
+ }
+ if *rawParams {
+ ss[0], err = cnp.Unescape([]byte(ss[0]))
+ checkerr(err)
+ ss[1], err = cnp.Unescape([]byte(ss[1]))
+ checkerr(err)
+ }
+ req.SetParam(ss[0], ss[1])
+ }
+
+ send(req, *printReq, *printHdr || *noBody, !*noBody)
+}