I am working with Unity3d and am trying to send a GET request to an API that requires the Date request header.
However UnityWebRequest does not send it automatically (I have checked with https://requestb.in/) and I cannot set it manually since "date" is one of the protected headers.
UnityWebRequest www = UnityWebRequest.Get (fullURL);
www.SetRequestHeader("Date", dateTimeString);
yield return www.Send();
and I get the following error:
ArgumentException: Cannot set Request Header Date - name contains illegal characters or is not user-overridable
I am able to communicate with the API successfully if I use the WWW class (which does allow me to set the "date" header manually) but am trying to do the same with the UnityWebRequest since WWW will be deprecated soon.
I tried to use System.Reflection's "InternalSetRequestHeader" (as implemented in https://forum.unity3d.com/threads/unitywebrequest-cookies.383530/#post-2621262) as follows:
System.Reflection.MethodInfo dynMethod = myReq.GetType ().GetMethod ("InternalSetRequestHeader", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance);
dynMethod.Invoke (myReq, new object[]{"Date", dateTimeString });
but then I get the following error:
InvalidOperationException: Cannot override system-specified headers
So, how can I make sure that the "date" request header is sent?
Is there a solution or do I have to use an object from a different library such as .NET's HttpWebRequest?
With UnityWebRequest you can't set custom values fro Date field, check docs.
Also, check RFC 2616, section 4.2, in particular RFC 2616, section 14.18 about Date header. Also, check RFC 2616 section 3.3.1.
Are you sure your dateTimeString is in correct format?
Related
I'm working on a Delphi REST client for a public API that requires an HMAC256/Base64 signed string to be added to the headers of the request to authenticate. I've spent hours trying to figure out why it's not working, so I compared the raw request from my Delphi client to that of a working C# library (using Wireshark).
It turns out my request matches perfectly the request generated by the working C# library, except that Delphi's REST client is URL-encoding the values added to the request's header, therefore invalidating the carefully crafted signature.
This is how I'm adding the signature string to the header:
RESTRequest1.Params.AddHeader('SIGNATURE', FSignature);
The signature string may have slashes, plus signs, and/or equal signs that are being URL-encoded when they shouldn't. For example when the value of the signature string is...
FSignature = '8A1BgACL9kB6P/kXuPdm99s05whfkrOUnEziEtU+0OY=';
...then the request should should output raw headers like...
GET /resource HTTP/1.1
User-Agent: Embarcadero URI Client/1.0
Connection: Keep-Alive
<snip>
SIGNATURE: 8A1BgACL9kB6P/kXuPdm99s05whfkrOUnEziEtU+0OY=
<snip>
...but instead Wireshark shows this as the real value being sent...
SIGNATURE: 8A1BgACL9kB6P%2FkXuPdm99s05whfkrOUnEziEtU%2B0OY%3D
Is there a way to prevent the URL-encoding of values when using AddHeader? Or maybe another way to add raw headers to a TRESTClient request?
PS: I already tried both TRESTRequest.Params.AddHeader and TRESTClient.AddParameter with TRESTRequestParameterKind.pkHTTPHEADER as the Kind parameter. Both resulted in URL-encoded values.
PS2: Using Delphi RAD Studio 10.3.
You should include poDoNotEncode in the Options property of the TRESTRequestParameter.
This can be done using:
RESTClient1.AddParameter('SIGNATURE', FSignature, pkHTTPHEADER, [poDoNotEncode]);
or by using:
RESTClient1.Params.AddHeader('SIGNATURE', FSignature).Options := [poDoNotEncode];
I am using AWS API Gateway and I want to set my Integration type to http. I have the integrated url as https:// xxxxxx.com which takes a header "apikey". I am not expecting the end user to pass the header rather I want to set the apikey to some constant value.
I see that there is a way to force the user to make him pass the header(by making header required under the Method Request section. However, I want to set it to default.
For example in all the requests which are internally calling the URL inside the API gateway should pass the header value as "12345".
You can add/remove/override headers with an Integration Request Mapping Template.
In the API Gateway console, chose the relevant api/resourece/method. Go to Integration Request > Mapping Templates and chose your Content-Type (if requests are going to be received without a Content-Type header, set the Content-Type for the mapping template to application/json, which is the default behaviour).
Then in the actual mapping template add the following:
{
#set($context.requestOverride.header.apikey= "testMe")
}
This will add (or overwrite if it already exists) a header called apikey with the value "testMe" to all http requests downstream.
If you take this route, then you will need to also map over any other headers, path parameters, query parameters or body that you wish to pass through.
You could loop through the headers and query parameters like this.
## First set the header you are adding
#set($context.requestOverride.header.apikey= "testMe")
## Loop through all incoming headers and set them for downstream request
#foreach($param in $input.params().header.keySet())
#set($context.requestOverride.header[$param]= $input.params().header.get($param))
#if($foreach.hasNext) #end
#end
## Loop through all incoming query parameters and set them for downstream request
#foreach($param in $input.params().querystring.keySet())
#set($context.requestOverride.querystring[$param]= $input.params().querystring.get($param))
#if($foreach.hasNext) #end
#end
As you need to ensure that the header apikey is set to a default value, you should set the override for apikey before looping through the rest of the headers as only the first override will take effect.
The relevant AWS documentation can be found here.
The other alternative would be to point your API Gateway at a Lambda and make the call from the Lambda instead.
Firstly thanks to #KMO for his help. The following is the solution:-
Enable Http Proxy Integration.
Add the headers apikey=xxxx and Accept-Encoding=identity under the same Integration
Request -> Http Headers.
Under Settings -> Binary Media Types set the following as separate Binary Media Types
'*', */*. I mean as two different lines.This step is needed to resolve the Gzip action while returning the response.
Add the Query parameter country in the URL Query String Parameters section.
In the Integration Request map the country parameter to ctry by adding the value under mapped from as method.request.querystring.country. This will ensure that the query parameter country you passed in the main URL will be fed to the downstream url as parameter ctry.
The advantage of this apporoach is that, even if you override the header apikey, the one set under the Http Headers will take the precedence.
I am following this MSDN Reference (https://learn.microsoft.com/en-us/rest/api/storageservices/fileservices/put-block) to implement a rest call for Put Block.
I am coding in Java and I formed below Authorisation string and URL before signing.
PUT
364070
x-ms-blob-type:BlockBlob
x-ms-date:Fri, 20 Jan 2017 12:57:06 GMT
x-ms-version:2016-05-31
/xyz/mycontainer/imageBlock1
comp:block
sun.net.www.protocol.https.DelegateHttpsURLConnection:https://xyz.blob.core.windows.net/mycontainer/imageBlock1?comp=block&blockid=YmxvY2stMQ==
Error I am getting:
403
Server failed to authenticate the request. Make sure the value of Authorization header is formed correctly including the signature.
I read gaurav mantras post http://gauravmantri.com/2013/02/16/uploading-large-files-in-windows-azure-blob-storage-using-shared-access-signature-html-and-javascript/. But, its not working for me.
Is there anything wrong with the string I am sending to sign or URL or
below httpConn Request Header.
The Http Header I am setting is:
httpConn.setRequestMethod("PUT");
httpConn.setRequestProperty("x-ms-blob-type", blobType);
httpConn.setRequestProperty("x-ms-date", date);
httpConn.setRequestProperty("x-ms-version", storageServiceVersion);
httpConn.setRequestProperty("Authorization", authorizationHeader);
httpConn.setRequestProperty("Content-Length",String.valueOf(blobLength) );
System.out.println(httpConn);
DataOutputStream wr = new DataOutputStream(httpConn.getOutputStream());
wr.write(bytes);
wr.flush();
wr.close();
int response = httpConn.getResponseCode();
As I known, Put Block is a operation against Block Blobs. So, we do not need to specify x-ms-blob-type header. If you specify this in your HTTP header, you need to follow the following tutorial about constructing the Canonicalized Headers String:
Retrieve all headers for the resource that begin with x-ms-, including the x-ms-date header.
Convert each HTTP header name to lowercase.
Sort the headers lexicographically by header name, in ascending order. Each header may appear only once in the string.
Finally, append a new-line character to each canonicalized header in the resulting list. Construct the CanonicalizedHeaders string by concatenating all headers in this list into a single string.
So, based on your code, your canonicalized headers string looks like:
x-ms-blob-type:BlockBlob\nx-ms-date:Fri, 20 Jan 2017 12:57:06 GMT\nx-ms-version:2016-05-31\n
Moreover, the CanonicalizedResource you built is incorrect. Based on your code, it should look as follows:
/{account-name}/{container-name}/{blob-name}\nblockid:{block-id}\ncomp:block
Note: For more details about constructing the Canonicalized Resource String, you could refer to this official document.
The StringToSign would look like this:
And the traffic captured by Fiddler as follows:
I need to update an order which is done via PUT method passing the order id as part of the https url string and a single parameter, the status_id.
https://mystore.mybigcommerce.com/orders/12345.json
I have tried several methods to pass the status_id value but no matter what I try "status_id=12" or formatted as JSON "{"status_id": 12,}" I always get the same response:
[{"status":415,"message":"The specified input content type is not valid."}]
I have also tried as a POST request passing the JSON or XML code as raw data but that method is not supported.
How am I supposed to pass that field=value pair? can I embed it in the url string?
I also tried it but it wouldn't work for me.
Any ideas?
In case you are wondering I am doing it within FileMaker with TROIUrl plugIn, not a very popular technology, but the GET method retrieving orders works like a charm
TURL_Put( ""; $url ;"status_id=12") (I have also tried other FM plugIns to no avail)
Don't get too caught up in the Filemaker part, I don't expect many people out there to be familiar with BigCommerce and Filemaker. I just need a generic answer.
Thanks
Commandline tool curl is worth a try. It supports put and https.
Mac OS X: curl already installed, call from FileMaker via AppleScript do shell script.
Windows: must be installed, call via Powershell.
It works for me using { "status_id": "3" } which means you probably need to put quotes around the actual number.
Also, it is a PUT operation and application/json which is part of the request content.
The error message received by the OP:
[{"status":415,"message":"The specified input content type is not valid."}]
Is saying that he did not supply the 'Content-Type' header in his request or that the header supplied is for a content type that is not allowed. For the OP's case using JSON he would need to include the header:
Content-Type: application/json
in his HTTPS request. This description can be found along with those of the other status codes you may see here:
https://developer.bigcommerce.com/api/status-codes
I am trying to produce both xml and json from my rest service.
#Produces({"application/xml", "application/json"})
However, when I try to use the service using curl/SOAPUI, I get back either xml or json depending on which is mentioned first. In simple words, only the first method is considered. Is there a workaround?
You should check this link out - oracle docs for #Produces
The spec says that it does indeed default to the first one if that is acceptable as specified by the media type on the request. You should check your soapUI tool and see what headers you are sending. If they are both being sent you will get a response with the first one listed in your #Produces annotation.