github.com/zignig/go-ipfs@v0.0.0-20141111235910-c9e5fdf55a52/commands/http/parse.go (about) 1 package http 2 3 import ( 4 "errors" 5 "net/http" 6 "strings" 7 8 cmds "github.com/jbenet/go-ipfs/commands" 9 ) 10 11 // Parse parses the data in a http.Request and returns a command Request object 12 func Parse(r *http.Request, root *cmds.Command) (cmds.Request, error) { 13 if !strings.HasPrefix(r.URL.Path, ApiPath) { 14 return nil, errors.New("Unexpected path prefix") 15 } 16 path := strings.Split(strings.TrimPrefix(r.URL.Path, ApiPath+"/"), "/") 17 18 stringArgs := make([]string, 0) 19 20 cmd, err := root.Get(path[:len(path)-1]) 21 if err != nil { 22 // 404 if there is no command at that path 23 return nil, ErrNotFound 24 25 } else if sub := cmd.Subcommand(path[len(path)-1]); sub == nil { 26 if len(path) <= 1 { 27 return nil, ErrNotFound 28 } 29 30 // if the last string in the path isn't a subcommand, use it as an argument 31 // e.g. /objects/Qabc12345 (we are passing "Qabc12345" to the "objects" command) 32 stringArgs = append(stringArgs, path[len(path)-1]) 33 path = path[:len(path)-1] 34 35 } else { 36 cmd = sub 37 } 38 39 opts, stringArgs2 := parseOptions(r) 40 stringArgs = append(stringArgs, stringArgs2...) 41 42 args := make([]interface{}, 0) 43 44 // count required argument definitions 45 lenRequired := 0 46 for _, argDef := range cmd.Arguments { 47 if argDef.Required { 48 lenRequired++ 49 } 50 } 51 52 // count the number of provided argument values 53 valCount := len(stringArgs) 54 // TODO: add total number of parts in request body (instead of just 1 if body is present) 55 if r.Body != nil { 56 valCount += 1 57 } 58 59 for _, argDef := range cmd.Arguments { 60 // skip optional argument definitions if there aren't sufficient remaining values 61 if valCount <= lenRequired && !argDef.Required { 62 continue 63 } else if argDef.Required { 64 lenRequired-- 65 } 66 67 if argDef.Type == cmds.ArgString { 68 if argDef.Variadic { 69 for _, s := range stringArgs { 70 args = append(args, s) 71 } 72 valCount -= len(stringArgs) 73 74 } else if len(stringArgs) > 0 { 75 args = append(args, stringArgs[0]) 76 stringArgs = stringArgs[1:] 77 valCount-- 78 79 } else { 80 break 81 } 82 83 } else { 84 // TODO: create multipart streams for file args 85 args = append(args, r.Body) 86 } 87 } 88 89 if valCount-1 > 0 { 90 args = append(args, make([]interface{}, valCount-1)) 91 } 92 93 optDefs, err := root.GetOptions(path) 94 if err != nil { 95 return nil, err 96 } 97 98 req := cmds.NewRequest(path, opts, args, cmd, optDefs) 99 100 err = cmd.CheckArguments(req) 101 if err != nil { 102 return nil, err 103 } 104 105 return req, nil 106 } 107 108 func parseOptions(r *http.Request) (map[string]interface{}, []string) { 109 opts := make(map[string]interface{}) 110 var args []string 111 112 query := r.URL.Query() 113 for k, v := range query { 114 if k == "arg" { 115 args = v 116 } else { 117 opts[k] = v[0] 118 } 119 } 120 121 // default to setting encoding to JSON 122 _, short := opts[cmds.EncShort] 123 _, long := opts[cmds.EncLong] 124 if !short && !long { 125 opts[cmds.EncShort] = cmds.JSON 126 } 127 128 return opts, args 129 }