github.com/loggregator/cli@v6.33.1-0.20180224010324-82334f081791+incompatible/cf/commands/curl.go (about) 1 package commands 2 3 import ( 4 "bytes" 5 "encoding/json" 6 "errors" 7 "fmt" 8 "io/ioutil" 9 "os" 10 "path/filepath" 11 "strings" 12 13 "code.cloudfoundry.org/cli/cf/flagcontext" 14 "code.cloudfoundry.org/cli/cf/flags" 15 . "code.cloudfoundry.org/cli/cf/i18n" 16 17 "code.cloudfoundry.org/cli/cf/api" 18 "code.cloudfoundry.org/cli/cf/commandregistry" 19 "code.cloudfoundry.org/cli/cf/configuration/coreconfig" 20 "code.cloudfoundry.org/cli/cf/requirements" 21 "code.cloudfoundry.org/cli/cf/terminal" 22 "code.cloudfoundry.org/cli/cf/trace" 23 ) 24 25 type Curl struct { 26 ui terminal.UI 27 config coreconfig.Reader 28 curlRepo api.CurlRepository 29 pluginCall bool 30 } 31 32 func init() { 33 commandregistry.Register(&Curl{}) 34 } 35 36 func (cmd *Curl) MetaData() commandregistry.CommandMetadata { 37 fs := make(map[string]flags.FlagSet) 38 fs["i"] = &flags.BoolFlag{ShortName: "i", Usage: T("Include response headers in the output")} 39 fs["X"] = &flags.StringFlag{ShortName: "X", Usage: T("HTTP method (GET,POST,PUT,DELETE,etc)")} 40 fs["H"] = &flags.StringSliceFlag{ShortName: "H", Usage: T("Custom headers to include in the request, flag can be specified multiple times")} 41 fs["d"] = &flags.StringFlag{ShortName: "d", Usage: T("HTTP data to include in the request body, or '@' followed by a file name to read the data from")} 42 fs["output"] = &flags.StringFlag{Name: "output", Usage: T("Write curl body to FILE instead of stdout")} 43 44 return commandregistry.CommandMetadata{ 45 Name: "curl", 46 Description: T("Executes a request to the targeted API endpoint"), 47 Usage: []string{ 48 T(`CF_NAME curl PATH [-iv] [-X METHOD] [-H HEADER] [-d DATA] [--output FILE] 49 50 By default 'CF_NAME curl' will perform a GET to the specified PATH. If data 51 is provided via -d, a POST will be performed instead, and the Content-Type 52 will be set to application/json. You may override headers with -H and the 53 request method with -X. 54 55 For API documentation, please visit http://apidocs.cloudfoundry.org.`), 56 }, 57 Examples: []string{ 58 `CF_NAME curl "/v2/apps" -X GET -H "Content-Type: application/x-www-form-urlencoded" -d 'q=name:myapp'`, 59 `CF_NAME curl "/v2/apps" -d @/path/to/file`, 60 }, 61 Flags: fs, 62 } 63 } 64 65 func (cmd *Curl) Requirements(requirementsFactory requirements.Factory, fc flags.FlagContext) ([]requirements.Requirement, error) { 66 if len(fc.Args()) != 1 { 67 cmd.ui.Failed(T("Incorrect Usage. An argument is missing or not correctly enclosed.\n\n") + commandregistry.Commands.CommandUsage("curl")) 68 return nil, fmt.Errorf("Incorrect usage: %d arguments of %d required", len(fc.Args()), 1) 69 } 70 71 reqs := []requirements.Requirement{ 72 requirementsFactory.NewAPIEndpointRequirement(), 73 } 74 75 return reqs, nil 76 } 77 78 func (cmd *Curl) SetDependency(deps commandregistry.Dependency, pluginCall bool) commandregistry.Command { 79 cmd.ui = deps.UI 80 cmd.config = deps.Config 81 cmd.curlRepo = deps.RepoLocator.GetCurlRepository() 82 cmd.pluginCall = pluginCall 83 return cmd 84 } 85 86 func (cmd *Curl) Execute(c flags.FlagContext) error { 87 path := c.Args()[0] 88 headers := c.StringSlice("H") 89 90 var method string 91 var body string 92 93 if c.IsSet("d") { 94 method = "POST" 95 96 jsonBytes, err := flagcontext.GetContentsFromOptionalFlagValue(c.String("d")) 97 if err != nil { 98 return err 99 } 100 body = string(jsonBytes) 101 } 102 103 if c.IsSet("X") { 104 method = c.String("X") 105 } 106 107 reqHeader := strings.Join(headers, "\n") 108 109 responseHeader, responseBody, apiErr := cmd.curlRepo.Request(method, path, reqHeader, body) 110 if apiErr != nil { 111 return errors.New(T("Error creating request:\n{{.Err}}", map[string]interface{}{"Err": apiErr.Error()})) 112 } 113 114 if trace.LoggingToStdout && !cmd.pluginCall { 115 return nil 116 } 117 118 if c.Bool("i") { 119 cmd.ui.Say(responseHeader) 120 } 121 122 if c.String("output") != "" { 123 err := cmd.writeToFile(responseBody, c.String("output")) 124 if err != nil { 125 return errors.New(T("Error creating request:\n{{.Err}}", map[string]interface{}{"Err": err})) 126 } 127 } else { 128 if strings.Contains(responseHeader, "application/json") { 129 buffer := bytes.Buffer{} 130 err := json.Indent(&buffer, []byte(responseBody), "", " ") 131 if err == nil { 132 responseBody = buffer.String() 133 } 134 } 135 136 cmd.ui.Say(responseBody) 137 } 138 return nil 139 } 140 141 func (cmd Curl) writeToFile(responseBody, filePath string) (err error) { 142 if _, err = os.Stat(filePath); os.IsNotExist(err) { 143 err = os.MkdirAll(filepath.Dir(filePath), 0755) 144 } 145 146 if err != nil { 147 return 148 } 149 150 return ioutil.WriteFile(filePath, []byte(responseBody), 0644) 151 }