how to keep key case sensitive in request header using golang? - go

I am recently using golang library "net/http",while add some header info to request, I found that the header keys are changing, e.g
request, _ := &http.NewRequest("GET", fakeurl, nil)
request.Header.Add("MyKey", "MyValue")
request.Header.Add("MYKEY2", "MyNewValue")
request.Header.Add("DONT-CHANGE-ME","No")
however, when I fetch the http message package, I found the header key changed like this:
Mykey: MyValue
Mykey2: MyNewValue
Dont-Change-Me: No
I using golang 1.3, then how to keep key case sensitive or keep its origin looking?
thx.

The http.Header Add and Set methods canonicalize the header name when adding values to the header map. You can sneak around the canonicalization by adding values using map operations:
request.Header["MyKey"] = []string{"MyValue"}
request.Header["MYKEY2"] = []string{"MyNewValue"}
request.Header["DONT-CHANGE-ME"] = []string{"No"}
As long as you use canonical names for headers known to the transport, this should work.

Related

Disable json binding validation

I'm using gin for creating web services.
gin has Bind(&request) which validates the request based on the tags provided in struct.
If the validation fails, it returns an error.
But I want the invalid request to be logged. How do I get the request json?
type SignupRequest struct {
FirstName string `json:"first_name" binding:"required"`
AssociatedBank string `json:"associated_bank" binding:"required"`
}
...
srj := NewSignupRequest()
err = c.Bind(srj)
If the required fails, I won't have the request data to log.
Two options come to mind.
To do this all within Gin, use c.ShouldBindWithBody(...) which has a side effect of storing the request body in the context key/value map under the key gin.Context.BodyBytesKey. Here is the implementation of ShouldBindWithBody for reference:
https://github.com/gin-gonic/gin/blob/master/context.go#L711
Beyond that, you can access the request itself from the gin.Context as c.Request. This is a standard net/http.Request with all the available functionality listed here:
https://golang.org/pkg/net/http/#Request (reading body, headers, etc.).
For option 2, I haven't tested this myself, but I would expect that since c.Bind(...) is reading from the request body behind the scenes, you might find that reading from c.Request.Body after c.Bind() fails doesn't give you the full request body (it's already been at least partially, if not fully, read in c.Bind()). In that case, you may have to tweak your code to read from the request yourself into a byte buffer and then do the binding (marshalling) from the byte buffer to SignupRequest yourself. In that way, you'll have the raw bytes to log or do whatever else you want with if the binding fails.

Reading cookie from Wasm

I am attempting to read a cookie from Wasm but have not found any examples so I guessed, but I guessed wrong.
c := js.Global().Get("Cookie").Get("cookiename")
fmt.Println(c)
This gives me an error:
panic: syscall/js: call of Value.Get on undefined
Given that I have not found any documentation regarding reading cookies from Wasm.
Is this even possible?
There are three issues here:
the field is on document, not body
the field name is cookie, not Cookie
the cookie object is a string, you need to parse it to find the cookie by name.
To get the cookie string, use the following:
cookies := js.Global().Get("document").Get("cookie").String()
You will then need to process the string to iterate through the cookies and extract the one with the desired name. See Get cookie by name
As always with wasm, figure out the javascript code first then convert it to wasm.

How to pass multiple arguments to golang net rpc call

I am using net library in go and I want to make RPC call:
Client.Call("action", []string{"arg1", "arg2"}, &response)
But in JSON I see:
{"method":"action","params":[["arg1","arg2"]],"id":0}
Notice that arguments are enclosed with double square brackets.
In my case I need params to be a simple list:
{"method":"action","params":["arg1","arg2"],"id":0}
Any ideas how to accomplish this?
The codec that Go's JSON RPC uses on top of the rpc.Client will take whatever param you send and encode that as the first element of the array it uses for the params.
So the encoded request will always have a top level array with just one element, which will contain the params you sent, as you already noted.
See the WriteRequest function here:
https://golang.org/src/net/rpc/jsonrpc/client.go#L57
To achieve what you want, you can implement a custom rpc.ClientCodec.
The interface is documented here:
https://golang.org/pkg/net/rpc/#ClientCodec
You can borrow almost all of the implementation for the default JSON codec here:
https://golang.org/src/net/rpc/jsonrpc/client.go
And modify the params attribute of the request to read:
Params interface{} `json:"params"`
Then when writing your WriteRequest based on the standard one, you can just assign your params to the request params:
c.req.Params[0] = param
You can then use the rpc.NewClientWithCodec to create a client using your custom codec:
https://golang.org/pkg/net/rpc/#NewClientWithCodec

Do I have to add an after filter to change all response content-type to json?

I'm using laravel 4.2, I've recently discovered that I'm not getting 'content-type' : 'application/json' on all my API requests that are JSON.
So...
was this supposed to work out of the box or am I supposed to add a filter by myself?
my options are either changing all the responses in my code that are json to Response::json()
or
the easiest solution is adding an after filter that checks if the response is json and changes the headers
json_decode($response->getContent());
if ( json_last_error() == JSON_ERROR_NONE ) {
$response->headers->set('Content-Type','application/json');
}
this seems to add some extra overhead for each request. Is there a better way?
Laravel already has what you need.
Response::json($your_data)
read more about it in docs
Laravel checks if your data implement JsonableInterface or ArrayObject or it's just array and convert it to json and set headers.

Response.getMetaData().get("location") in jersey: Why does it return a list?

In my service I am executing the following line:
return Response.created("someuri").build();
Then in my client in order to get the location I have to do
response.getMetaData().get("location").get(0);
This is all good and well, but I am wondering why on earth that is returned as a List instead of just a URI. Can a jersey expert help me out here?
Thanks!
getMetaData() returns a map of Headers in the HTTP response, and while we'd expect only one value per key most of the time, the way the HTTP protocol lists Headers line by line, there is no enforcement that header names have to be unique, so the API reflects that in its MultivaluedMap.
Moreover while we'd expect a unique value for "Location", there are valid use cases for having multiple values for other types of headers such as "Set-Cookie".

Resources