golang, post with json fails, but multipart succeed - json

When I tried to send post with json,
401 error (unauthorized messages) showed.
But with multipart, then succeeded.
In the following code,
I could get the token with only requestTokenByBuff which includes multipart.
Everytime I send post with json, I got failed.
I tried to print json body, and there was no error.
No header with body also made same result(401 error).
I did not test http.Post because Header should be inputed.
Why does post with json fail?
type AuthConfig struct {
ClientId string `json:"client_id"`
ClientSecret string `json:"client_secret"`
Code string `json:"data"`
GrantType string `json:"grant_type"`
}
var host string
func initAuthConfig(a *AuthConfig) {
host = "https://xxxxxxx"
a.ClientId = "xxxxxxx"
a.ClientSecret = "xxxxxxx"
a.Code = "xxxxx"
a.GrantType = "xxxx"
}
func initAuthConfig2() {
host = "https://xxxxxxx"
}
func requestToken(auth *AuthConfig) {
authbytes, _ := json.Marshal(auth)
authbuff := bytes.NewBuffer(authbytes)
client := &http.Client{}
req, err := http.NewRequest("POST", host, authbuff)
if err != nil {
log.Fatalln(err)
}
req.Header.Add("User-Agent", "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.xxxxxx")
req.Header.Add("Cookie", "SCOUTER=xxxxxxx")
req.Header.Add("Content-Type", "application/json")
resp, err := client.Do(req)
if err != nil {
log.Fatalln(err)
}
defer resp.Body.Close()
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
log.Fatalln(err)
}
data := string(body)
fmt.Println(data)
}
func requestTokenByBuff(buff *bytes.Buffer) {
writer := multipart.NewWriter(buff)
_ = writer.WriteField("client_id", "xxxxxxxxxx")
_ = writer.WriteField("client_secret", "xxxxxxxx")
_ = writer.WriteField("data", "xxxxxx")
_ = writer.WriteField("grant_type", "xxxxxxx")
err := writer.Close()
if err != nil {
log.Fatalln(err)
return
}
client := &http.Client{}
req, err := http.NewRequest("POST", host, buff)
if err != nil {
log.Fatalln(err)
}
req.Header.Add("User-Agent", "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.xxxx")
req.Header.Add("Cookie", "SCOUTER=xxxxxxxx")
req.Header.Set("Content-Type", writer.FormDataContentType())
resp, err := client.Do(req)
if err != nil {
log.Fatalln(err)
}
defer resp.Body.Close()
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
log.Fatalln(err)
}
data := string(body)
fmt.Println(data)
}
func main() {
// config := new(AuthConfig)
// initAuthConfig(config)
// requestToken(config)
buff := &bytes.Buffer{}
initAuthConfig2()
requestTokenByBuff(buff)
}

Related

How to set up web server to perform POST Request in Go?

I want to set up a web server to perform a POST request. How does the post request get executed with the code below since only HandleFunc and ListenAndServe are defined in main function?
package main
import (
"fmt"
"io/ioutil"
"log"
"net/http"
"strings"
)
func post(w http.ResponseWriter, r *http.Request) {
const myurl string = "http://localhost:8000/"
request := strings.NewReader(`
{
"Name":"Tom",
"Age":"20"
}
`)
response, err := http.Post(myurl, "application/json", request)
content, err := ioutil.ReadAll(response.Body)
if err != nil {
panic(err)
}
fmt.Println(string(content))
defer response.Body.Close()
}
func main() {
http.HandleFunc("/", post)
log.Fatal(http.ListenAndServe(":8000", nil))
}
Here is a basic example of how you could go about it. I am using the same program to run both, the server and the client. This is just for demonstration purposes. You can of course make them separate programs.
// use struct to represent the data
// to recieve and send
type Person struct {
Name string `json:"name"`
Age int `json:"age"`
}
// run the example
func main() {
// start the server in a goroutine
go server()
// wait 1 second to give the server time to start
time.Sleep(time.Second)
// make a post request
if err := client(); err != nil {
fmt.Println(err)
}
}
// basic web server to receive a request and
// decode the body into a user struct
func server() {
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
if r.Method != http.MethodPost {
http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
return
}
user := &Person{}
err := json.NewDecoder(r.Body).Decode(user)
if err != nil {
http.Error(w, err.Error(), http.StatusBadRequest)
return
}
fmt.Println("got user:", user)
w.WriteHeader(http.StatusCreated)
})
if err := http.ListenAndServe(":8080", nil); err != http.ErrServerClosed {
panic(err)
}
}
// a simple client that posts a user to the server
func client() error {
user := &Person{
Name: "John",
Age: 30,
}
b := new(bytes.Buffer)
err := json.NewEncoder(b).Encode(user)
if err != nil {
return err
}
resp, err := http.Post("http://localhost:8080/", "application/json", b)
if err != nil {
return err
}
defer resp.Body.Close()
fmt.Println(resp.Status)
return nil
}
Here is the working example: https://go.dev/play/p/34GT04jy_uA

Multipart request upload file and JSON message

How to implement a curl request in a go program
curl -XPOST -H 'Authorization: Bearer ***API*KEY***' http://127.0.0.1:9000/api/case/task/AVqqeXc9yQ6w1DNC8aDj/log -F '_json={"message": "Screenshot of fake site"};type=application/json' -F 'attachment=#screenshot1.png;type=image/png'
I tried to do something similar, but my knowledge is probably not enough
func CreateAttachedTask(caseid string, filename string, tasktitle string, taskdescription string, baseURL string, token string) {
fileDir, _ := os.Getwd()
filePath := path.Join(fileDir, filename)
file, err := os.Open(filePath)
defer file.Close()
buffer := new(bytes.Buffer)
writer := multipart.NewWriter(buffer)
part, _ := writer.CreateFormFile("filename", filepath.Base(file.Name()))
io.Copy(part, file)
writer.WriteField("_json", `{"message":"Screenshot of fake site"}`)
defer writer.Close()
req, err = http.NewRequest("POST", "http://127.0.0.1:9000/api/case/task/AVqqeXc9yQ6w1DNC8aDj/log", buffer)
if err != nil {
log.Fatal(err.Error())
}
req.Header.Set("Authorization", token)
req.Header.Set("Content-Type", writer.FormDataContentType())
client = &http.Client{Transport: defaultTtransportObs}
resp, err = client.Do(req)
if err != nil {
panic(err)
}
fmt.Println("Log response Status:", resp.Status)
defer resp.Body.Close()
}
Here is the solution
var b bytes.Buffer
w := multipart.NewWriter(&b)
file, err := os.Open(filename)
req.Header.Set("Authorization", token)
h := make(textproto.MIMEHeader)
h.Set("Content-Type", "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet")
h.Set("Content-Disposition", fmt.Sprintf(`form-data; name="attachment"; filename="%s"`, filename))
fileWriter, err := w.CreatePart(h)
if err != nil {
fmt.Println(err)
}
io.Copy(fileWriter, file)
w.WriteField("_json", `{"message":"Attach:"}`)
w.Close()
req, err = http.NewRequest("POST", "http://127.0.0.1:9000/api/case/task/AVqqeXc9yQ6w1DNC8aDj/log", &b)
if err != nil {
log.Fatal(err.Error())
}
req.Header.Set("Content-Type", w.FormDataContentType())
req.Header.Set("Authorization", token)
res, err := client.Do(req)
if err != nil {
log.Fatal(err.Error())
}
if res.StatusCode != http.StatusOK {
err = fmt.Errorf("bad status: %s", res.Status)
}

interface conversion: interface {} is int64, not []uint8

I'm trying to implement a go program which can handle http requests and send response in nested JSON. When i run my code and call the URL, I'm getting a runtime error,what does it mean? how can i handle this?
panic serving 192.168.0.101:50760: interface conversion: interface {} is int64, not []uint8
goroutine 5 [running]
This is my function code which is called on hitting the url
func logInPass(res http.ResponseWriter, req *http.Request) {
type Resp struct {
Result []map[string]interface{} `json:"Result,omitempty"`
Status string `json:"Status"`
}
type AxleUser struct {
Mobile string `json:"Mobile"`
Password string `json:"Password"`
}
var Response Resp
Response.Status = "failed"
Result := make(map[string]interface{})
db, err := sql.Open("mysql", "root:chikkIbuddI57#tcp(127.0.0.1:3306)/b2b")
if err != nil {
panic(err.Error())
}
defer db.Close()
rnd := render.New()
b, err := ioutil.ReadAll(req.Body)
defer req.Body.Close()
if err != nil {
panic(err.Error())
}
// Unmarshal the request body
var msg AxleUser
err = json.Unmarshal(b, &msg)
if err != nil {
panic(err.Error())
}
// get shop id from emp table using mobile number and password
userrows, usererr := db.Query("SELECT b2b_emp_id,b2b_shop_id,b2b_shop_name,b2b_emp_name,b2b_emp_mobile_number FROM b2b_employee_tbl WHERE b2b_emp_mobile_number=? and b2b_password=?", msg.Mobile, msg.Password)
if usererr != nil {
panic(usererr.Error())
}
usercolumns, usererr := userrows.Columns()
if usererr != nil {
panic(usererr.Error())
}
usercount := len(usercolumns)
values := make([]interface{}, usercount)
scanArgs := make([]interface{}, usercount)
for i := range values {
scanArgs[i] = &values[i]
}
for userrows.Next() {
usererr := userrows.Scan(scanArgs...)
if usererr != nil {
panic(usererr.Error())
}
for i, v := range values {
if v != nil {
Result[usercolumns[i]] = fmt.Sprintf("%s", string(v.([]byte)))
}
}
Response.Result = append(Response.Result, Result)
Response.Status = "success"
}
res.Header().Set("Content-Type", "application/json")
rnd.JSON(res, http.StatusOK, Response)
}
Thanks in Advance!
I've changed this line
values := make([]interface{}, usercount)
To
values := make([]string, usercount)
And this line
Result[usercolumns[i]] = fmt.Sprintf("%s", string(v.([]byte)))
To
Result[usercolumns[i]] = v

Set headers in JSON get request

I'm getting JSON resonse from an external API with the following way:
func Request(url string, contentType string) []byte {
resp, err := http.Get(url)
resp.Header.Set("Content-Type", contentType)
if err != nil {
log.Fatal(err)
}
body, err := ioutil.ReadAll(resp.Body)
resp.Body.Close()
if err != nil {
log.Fatal(err)
}
return body
}
url := fmt.Sprintf("https://example.com/api/category/%s", category)
contentType := "application/json"
body := Request(url, contentType)
res := &JSONRespStruct{}
err := json.Unmarshal([]byte(body), res)
if err != nil {
log.Fatal(err)
}
The problem if I start to benchmark my site with go-wrk, the server crashes with the following error message:
2018/01/02 12:13:35 invalid character '<' looking for beginning of value
I think the code try to parse the JSON response as HTML. How I can force to get the response as a JSON?
You probably want to set the header on the request. Setting the header on the response has no impact.
func Request(url string, contentType string) []byte {
req, err := http.NewRequest("GET", url, nil)
if err != nil {
log.Fatal(err)
}
req.Header.Set("Content-Type", contentType)
resp, err := http.DefaultClient.Do(req)
if err != nil {
log.Fatal(err)
}
defer resp.Body.Close()
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
log.Fatal(err)
}
return body
}

Golang Encode/Decode base64 with json post doesn't work

I build a client and a server in golang both are using this functions to encrypt/decrypt
func encrypt(text []byte) ([]byte, error) {
block, err := aes.NewCipher(key)
if err != nil {
return nil, err
}
b := base64.StdEncoding.EncodeToString(text)
ciphertext := make([]byte, aes.BlockSize+len(b))
iv := ciphertext[:aes.BlockSize]
if _, err := io.ReadFull(rand.Reader, iv); err != nil {
return nil, err
}
cfb := cipher.NewCFBEncrypter(block, iv)
cfb.XORKeyStream(ciphertext[aes.BlockSize:], []byte(b))
return ciphertext, nil
}
func decrypt(text []byte) ([]byte, error) {
block, err := aes.NewCipher(key)
if err != nil {
return nil, err
}
if len(text) < aes.BlockSize {
return nil, errors.New("ciphertext too short")
}
iv := text[:aes.BlockSize]
text = text[aes.BlockSize:]
cfb := cipher.NewCFBDecrypter(block, iv)
cfb.XORKeyStream(text, text)
data, err := base64.StdEncoding.DecodeString(string(text))
if err != nil {
return nil, err
}
return data, nil
}
so yeah I make a normal post request
url := "https://"+configuration.Server+configuration.Port+"/get"
// TODO maybe bugs rest here
ciphertext, err := encrypt([]byte(*getUrl))
if err != nil {
fmt.Println("Error: " + err.Error())
}
fmt.Println(string(ciphertext))
values := map[string]interface{}{"url": *getUrl, "urlCrypted": ciphertext}
jsonValue, _ := json.Marshal(values)
jsonStr := bytes.NewBuffer(jsonValue)
req, err := http.NewRequest("POST", url, jsonStr)
and the servercode is as following
requestContent := getRequestContentFromRequest(req)
url := requestContent["url"].(string)
undecryptedUrl := requestContent["urlCrypted"].(string)
decryptedurl, err := decrypt([]byte(undecryptedUrl))
if err != nil {
fmt.Println("Error: " + err.Error())
}
fmt.Println(decryptedurl)
where getRequestContentFromRequest is as following
func getRequestContentFromRequest(req *http.Request)
map[string]interface{} {
buf := new(bytes.Buffer)
buf.ReadFrom(req.Body)
data := buf.Bytes()
var requestContent map[string]interface{}
err := json.Unmarshal(data, &requestContent)
if err != nil {
fmt.Println(err)
}
return requestContent
}
Now to the problem.
If I encrypt my string in the client and decrypt it direct after that everything is fine.
But, when I send the encrypted string to the server and try to decrypt it with literrally the same function as in the client, the decrypt function throws an error.
Error: illegal base64 data at input byte 0
I think the Problem is the unmarshalling of the JSON.
Thanks for help.
P.S.
Repos are
github.com/BelphegorPrime/goSafeClient and github.com/BelphegorPrime/goSafe
UPDATE
Example JSON
{"url":"facebook2.com","urlCrypted":"/}\ufffd\ufffd\ufffdgP\ufffdN뼞\ufffd\u0016\ufffd)\ufffd\ufffd\ufffdy\u001c\u000f\ufffd\ufffd\ufffdep\ufffd\rY\ufffd\ufffd$\ufffd\ufffd"}
UPDATE2
I made a playground here
The problem is that you encode in base64 twice. The first time in the encrypt function and the second time during the JSON marshalling. byte slices are automatically converted into base64 strings by the encoding/json marshaller.
The solution is to decode the base64 string before calling decrypt.
Example on the Go PlayGround
EDIT
Working solution here