Golang Wasm HTTP Request Failing - http

I'm a little stuck on a Golang wasm request. The code works just fine in a service when I test it, but when I try to run it in a browser with wasm I get a fetch failed error. This code runs just fine if I call it from a stand-alone service:
go func() {
authURL := "https://auth.home.rsmachiner.com/login"
type loginStruct struct {
Username string `json:"username"`
Password string `json:"password"`
}
fmt.Println("Pushed login button")
fmt.Printf("Got Login: %v\n", r.LoginBoxValue)
fmt.Printf("Got Password: %v\n", r.PasswordValue)
var login loginStruct
login.Username = r.LoginBoxValue
login.Password = r.PasswordValue
data, err := json.Marshal(&login)
if err != nil {
fmt.Println(err)
}
fmt.Println(string(data))
req, _ := http.NewRequest("POST", authURL, bytes.NewBuffer(data))
client := &http.Client{}
resp, err := client.Do(req)
if err != nil {
fmt.Println("response error")
fmt.Println(err)
return
}
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
fmt.Println(err)
return
}
fmt.Print("BODY:")
fmt.Println(string(body))
}()
Which throws the following error:
Post "https://auth.home.rsmachiner.com/login": net/http: fetch() failed: Failed to fetch
When I try it from a standalone client it works fine. The server is allowing CORS as well with
w.Header().Set("Access-Control-Allow-Origin", "*")

For anyone that stumbles on this, it works fine in a browser too. The problem was the HTML not the code. The HTML was making the page reload so the request was failing due to being terminated.

Related

Getting the status code from a get request in golang

I'm trying to get the http status code in goland.
I'm passing the authorization token as well.
This is what I tried so far:
func StatusCode(PAGE string, AUTH string) (r string){
resp, err := http.NewRequest("GET", PAGE, nil)
if err != nil {
log.Fatal(err)
}
resp.Header.Set("Authorization", AUTH)
fmt.Println("HTTP Response Status:", resp.StatusCode, http.StatusText(resp.StatusCode))
r := resp.StatusCode + http.StatusText(resp.StatusCode)
}
Basically I want to get this:
r = "200 OK"
or
r= "400 Bad request"
The previous code it´s complaining from resp.StatusCode and http.StatusText(resp.StatusCode)
There are two problems. The first is that the application uses the request as the response. Execute the request to get the response.
The second problem is that resp.StatusCode + http.StatusText(resp.StatusCode) does not compile because operand types are mismatched. The value resp.StatusCode is an int. The value of http.StatusText(resp.StatusCode) is a string. Go does not have the implicit conversion of numbers to strings that would make this work the way you expect.
Use r := resp.Status if you want the status string as sent from the server.
Use r := fmt.Sprintf("%d %s", resp.StatusCode, http.StatusText(resp.StatusCode)) to construct a status string from the server's status code and the Go's status strings.
Here's the code:
func StatusCode(PAGE string, AUTH string) (r string) {
// Setup the request.
req, err := http.NewRequest("GET", PAGE, nil)
if err != nil {
log.Fatal(err)
}
req.Header.Set("Authorization", AUTH)
// Execute the request.
resp, err := http.DefaultClient.Do(req)
if err != nil {
return err.Error()
}
// Close response body as required.
defer resp.Body.Close()
fmt.Println("HTTP Response Status:", resp.StatusCode, http.StatusText(resp.StatusCode))
return resp.Status
// or fmt.Sprintf("%d %s", resp.StatusCode, http.StatusText(resp.StatusCode))
}

MissingContentLength response from Minio on PUT to presigned URL

When trying to perform a PUT request to a pre-signed Minio URL using the golang httpClient library the following error is returned:
<Error><Code>MissingContentLength</Code><Message>You must provide the Content-Length HTTP header.</Message><Key>obj</Key><BucketName>bucket</BucketName><Resource>/bucket/obj</Resource><RequestId>REMOVED</RequestId><HostId>REMOVED</HostId></Error>
I'm trying to upload a file to the URL created by running the following on a connected minioClient:
minioClient.PresignedPutObject(context.Background(), "bucket", "obj", time.Second*60)
The code which is erroring is:
url := "http://pre-signed-url-to-bucket-obj"
fileName := "test.txt"
file, err := os.Open(fileName)
if err != nil {
log.Fatal(err)
}
defer file.Close()
request, err := http.NewRequest(http.MethodPut, url, file)
if err != nil {
log.Fatal("Error creating request:", err)
}
// Tried including and excluding explicit Content-Length add, doesn't change response
// fStat, err := file.Stat()
// if err != nil {
// log.Fatal("Error getting file info:", err)
// }
// request.Header.Set("Content-Length", strconv.FormatInt(fStat.Size(), 10))
client := &http.Client{}
resp, err := client.Do(request)
if err != nil {
log.Fatal("Error performing request:", err)
}
defer resp.Body.Close()
content, err := ioutil.ReadAll(resp.Body)
if err != nil {
log.Fatal("Error reading response:", err)
}
log.Println(string(content))
I've checked the Request and from what I'm able to tell Content-Length is being added.
A curl call with the --upload-file option specified will work:
curl -X PUT 'http://pre-signed-url-to-bucket-obj' --upload-file test.txt
I'm able to verify Content-Length is correctly added.
I would like to avoid a form as it does weird stuff to the obj on Minio's end.
Any help is much appreciated!
Do this to explicit content-length explicitly:
request.ContentLength = fStat.Size()
I verified that the above code works with this fix

Issuing HTTP Get Request in Flexible Environment in App Engine

I am using Flexible Environment in App engine I want to send HTTP Get request in my code.
ctx := appengine.NewContext(r)
client := urlfetch.Client(ctx)
req, err := http.NewRequest("GET", "https://www.google.com/", nil)
res, err := client.Do(req)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
fmt.Fprintf(w, "HTTP GET returned status %v", res.Status)
When I run app I get the following error:
https://www.google.com/: not an App Engine context
The above code works in Standard Environment and but it is not working in flexible environment.
You don't need URL Fetch in App Engine Flexible, you can simply issue the http request: https://cloud.google.com/appengine/docs/flexible/go/migrating#url_fetch

How to get a cookie from a HTTP Get request to a consecutive HTTP Post request

For testing I like to simulate signups. I get the signup page, fill in the form and post it. Apparently the session cookie that is provided by the server is not sent in the post request. If I access the server from a web browser all works fine. I can see that the response to Get contains the cookie. How can I add it to the PostForm?
func signup(name string, ret chan bool) {
var xsrf string
fmt.Println("Starting signup with", name)
response, err := http.Get("http://localhost:8080/signup")
if err != nil {
panic(err)
} else {
defer response.Body.Close()
buffer, _ := ioutil.ReadAll(response.Body)
xsrf = regXsrf.FindStringSubmatch(string(buffer))[1]
}
data := url.Values{}
data.Set("name", name)
data.Add("password", "111222")
data.Add("password2", "111222")
data.Add("groupcode", "AllesWirdGut")
data.Add("websocketstoken", xsrf)
response, err = http.PostForm("http://localhost:8080/signup", data)
if err != nil {
panic(err)
} else {
defer response.Body.Close()
}
}

How Can I Make the Go HTTP Client NOT Follow Redirects Automatically?

I'm currently writing some software in Go that interacts with a REST API. The REST API endpoint I'm trying to query returns an HTTP 302 redirect along with an HTTP Location header, pointing to a resource URI.
I'm trying to use my Go script to grab the HTTP Location header for later processing.
Here's what I'm currently doing to achieve this functionality:
package main
import (
"errors"
"fmt"
"io/ioutil"
"net/http"
)
var BASE_URL = "https://api.example.com/v1"
var STORMPATH_API_KEY_ID = "xxx"
var STORMPATH_API_KEY_SECRET = "xxx"
func noRedirect(req *http.Request, via []*http.Request) error {
return errors.New("Don't redirect!")
}
func main() {
client := &http.Client{
CheckRedirect: noRedirect
}
req, err := http.NewRequest("GET", BASE_URL+"/tenants/current", nil)
req.SetBasicAuth(EXAMPLE_API_KEY_ID, EXAMPLE_API_KEY_SECRET)
resp, err := client.Do(req)
// If we get here, it means one of two things: either this http request
// actually failed, or we got an http redirect response, and should process it.
if err != nil {
if resp.StatusCode == 302 {
fmt.Println("got redirect")
} else {
panic("HTTP request failed.")
}
}
defer resp.Body.Close()
}
This feels like a bit of a hack to me. By overriding the http.Client's CheckRedirect function, I'm essentially forced to treat HTTP redirects like errors (which they aren't).
I've seen several other places suggesting to use an HTTP transport instead of an HTTP client -- but I'm not sure how to make this work since I need the HTTP Client as I need to use HTTP Basic Auth to communicate with this REST API.
Can any of you tell me a way to make HTTP requests with Basic Authentication -- while not following redirects -- that doesn't involve throwing errors and error handling?
There's a much simpler solution right now:
client := &http.Client{
CheckRedirect: func(req *http.Request, via []*http.Request) error {
return http.ErrUseLastResponse
},
}
This way, the http package automatically knows: "Ah, I shouldn't follow any redirects", but does not throw any error. From the comment in the source code:
As a special case, if CheckRedirect returns ErrUseLastResponse,
then the most recent response is returned with its body
unclosed, along with a nil error.
Another option, using the client itself, without the RoundTrip:
// create a custom error to know if a redirect happened
var RedirectAttemptedError = errors.New("redirect")
client := &http.Client{}
// return the error, so client won't attempt redirects
client.CheckRedirect = func(req *http.Request, via []*http.Request) error {
return RedirectAttemptedError
}
// Work with the client...
resp, err := client.Head(urlToAccess)
// test if we got the custom error
if urlError, ok := err.(*url.Error); ok && urlError.Err == RedirectAttemptedError{
err = nil
}
UPDATE: this solution is for go < 1.7
It is possible, but the solution inverts the problem a little. Here's a sample written up as a golang test.
package redirects
import (
"github.com/codegangsta/martini-contrib/auth"
"github.com/go-martini/martini"
"net/http"
"net/http/httptest"
"testing"
)
func TestBasicAuthRedirect(t *testing.T) {
// Start a test server
server := setupBasicAuthServer()
defer server.Close()
// Set up the HTTP request
req, err := http.NewRequest("GET", server.URL+"/redirect", nil)
req.SetBasicAuth("username", "password")
if err != nil {
t.Fatal(err)
}
transport := http.Transport{}
resp, err := transport.RoundTrip(req)
if err != nil {
t.Fatal(err)
}
// Check if you received the status codes you expect. There may
// status codes other than 200 which are acceptable.
if resp.StatusCode != 200 && resp.StatusCode != 302 {
t.Fatal("Failed with status", resp.Status)
}
t.Log(resp.Header.Get("Location"))
}
// Create an HTTP server that protects a URL using Basic Auth
func setupBasicAuthServer() *httptest.Server {
m := martini.Classic()
m.Use(auth.Basic("username", "password"))
m.Get("/ping", func() string { return "pong" })
m.Get("/redirect", func(w http.ResponseWriter, r *http.Request) {
http.Redirect(w, r, "/ping", 302)
})
server := httptest.NewServer(m)
return server
}
You should be able to put the above code into it's own package called "redirects" and run it after fetching the required dependencies using
mkdir redirects
cd redirects
# Add the above code to a file with an _test.go suffix
go get github.com/codegangsta/martini-contrib/auth
go get github.com/go-martini/martini
go test -v
Hope this helps!
To make request with Basic Auth that does not follow redirect use RoundTrip function that accepts *Request
This code
package main
import (
"fmt"
"io/ioutil"
"net/http"
"os"
)
func main() {
var DefaultTransport http.RoundTripper = &http.Transport{}
req, _ := http.NewRequest("GET", "http://httpbin.org/headers", nil)
req.SetBasicAuth("user", "password")
resp, _ := DefaultTransport.RoundTrip(req)
defer resp.Body.Close()
contents, err := ioutil.ReadAll(resp.Body)
if err != nil {
fmt.Printf("%s", err)
os.Exit(1)
}
fmt.Printf("%s\n", string(contents))
}
outputs
{
"headers": {
"Accept-Encoding": "gzip",
"Authorization": "Basic dXNlcjpwYXNzd29yZA==",
"Connection": "close",
"Host": "httpbin.org",
"User-Agent": "Go 1.1 package http",
"X-Request-Id": "45b512f1-22e9-4e49-8acb-2f017e0a4e35"
}
}
As an addition of top rated answer,
You can control the particle size
func myCheckRedirect(req *http.Request, via []*http.Request, times int) error {
err := fmt.Errorf("redirect policy: stopped after %d times", times)
if len(via) >= times {
return err
}
return nil
}
...
client := &http.Client{
CheckRedirect: func(req *http.Request, via []*http.Request) error {
return myCheckRedirect(req, via, 1)
},
}
ref: https://golangbyexample.com/http-no-redirect-client-golang/

Resources