commands/http: Added stream argument handling to client and request parser
Matt Bell committed
Nov 2, 2014 at 17:58 UTC
40858b43edc65539fb4c27991b408260e090ef51
2 files changed
+45
-17
commands/http/client.go
+22
-6
@@ -6,6 +6,7 @@ import (
6
"fmt"
7
"io"
8
"net/http"
9
+ "os"
10
"strings"
11
12
ma "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr"
@@ -14,7 +15,7 @@ import (
15
cmds "github.com/jbenet/go-ipfs/commands"
16
)
17
17
-const ApiPath = "/api/v0"
18
+const ApiPath = "/api/v0" // TODO: make configurable
19
20
func Send(req cmds.Request) (cmds.Response, error) {
21
addr, err := ma.NewMultiaddr(req.Context().Config.Addresses.API)
@@ -40,18 +41,33 @@ func Send(req cmds.Request) (cmds.Response, error) {
41
req.SetOption(cmds.EncLong, cmds.JSON)
42
}
43
44
+ // TODO: handle multiple files with multipart
45
+ var in io.Reader
46
+
47
query := "?"
48
for k, v := range req.Options() {
49
query += "&" + k + "=" + v.(string)
50
}
47
- for _, arg := range req.Arguments() {
48
- s, ok := arg.(string)
49
- if ok {
50
- query += "&arg=" + s
51
+
52
+ args := req.Arguments()
53
+ for i, arg := range args {
54
+ if req.Command().Arguments[i].Type == cmds.ArgString {
55
+ query += "&arg=" + arg.(string)
56
+
57
+ } else {
58
+ // TODO: multipart
59
+ if in != nil {
60
+ return nil, fmt.Errorf("Currently, only one file stream is possible per request")
61
+ }
62
+ in, err = os.Open(arg.(string))
63
+ if err != nil {
64
+ return nil, err
65
+ }
66
+ args[i] = in
67
}
68
}
69
54
- httpRes, err := http.Post(url+query, "application/octet-stream", nil)
70
+ httpRes, err := http.Post(url+query, "application/octet-stream", in)
71
if err != nil {
72
return nil, err
73
}
commands/http/parse.go
+23
-11
@@ -10,7 +10,7 @@ import (
10
// Parse parses the data in a http.Request and returns a command Request object
11
func Parse(r *http.Request, root *cmds.Command) (cmds.Request, error) {
12
path := strings.Split(r.URL.Path, "/")[3:]
13
- args := make([]interface{}, 0)
13
+ stringArgs := make([]string, 0)
14
15
cmd, err := root.Get(path[:len(path)-1])
16
if err != nil {
@@ -24,36 +24,48 @@ func Parse(r *http.Request, root *cmds.Command) (cmds.Request, error) {
24
25
// if the last string in the path isn't a subcommand, use it as an argument
26
// e.g. /objects/Qabc12345 (we are passing "Qabc12345" to the "objects" command)
27
- args = append(args, path[len(path)-1])
27
+ stringArgs = append(stringArgs, path[len(path)-1])
28
path = path[:len(path)-1]
29
30
} else {
31
cmd = sub
32
}
33
34
- opts, args2 := parseOptions(r)
35
- args = append(args, args2...)
34
+ opts, stringArgs2 := parseOptions(r)
35
+ stringArgs = append(stringArgs, stringArgs2...)
36
+
37
+ // Note that the argument handling here is dumb, it does not do any error-checking.
38
+ // (Arguments are further processed when the request is passed to the command to run)
39
+ args := make([]interface{}, len(cmd.Arguments))
40
+ for i, arg := range cmd.Arguments {
41
+ if arg.Type == cmds.ArgString {
42
+ if len(stringArgs) > 0 {
43
+ args[i] = stringArgs[0]
44
+ stringArgs = stringArgs[1:]
45
+ }
46
+
47
+ } else {
48
+ // TODO: create multipart streams for file args
49
+ args[i] = r.Body
50
+ }
51
+ }
52
53
return cmds.NewRequest(path, opts, args, cmd), nil
54
}
55
40
-func parseOptions(r *http.Request) (map[string]interface{}, []interface{}) {
56
+func parseOptions(r *http.Request) (map[string]interface{}, []string) {
57
opts := make(map[string]interface{})
42
- args := make([]interface{}, 0)
58
+ var args []string
59
60
query := r.URL.Query()
61
for k, v := range query {
62
if k == "arg" {
47
- for _, s := range v {
48
- args = append(args, interface{}(s))
49
- }
63
+ args = v
64
} else {
65
opts[k] = v[0]
66
}
67
}
68
55
- // TODO: create multipart streams for file args
56
-
69
// default to setting encoding to JSON
70
_, short := opts[cmds.EncShort]
71
_, long := opts[cmds.EncLong]