I'm working on AS3 multipart uploader. I'm using this documentation http://docs.amazonwebservices.com/AmazonS3/latest/dev/index.html?RESTAuthentication.html for building signature. Here is my example:
Request:
POST /btnOK.png?uploads HTTP/1.1
Referer: app:/Main.swf
Accept: text/xml, application/xml, application/xhtml+xml, text/html;q=0.9, text/plain;q=0.8, text/css, image/png, image/jpeg, image/gif;q=0.8, application/x-shockwave-flash, video/mp4;q=0.9, flv-application/octet-stream;q=0.8, video/x-flv;q=0.7, audio/mp4, application/futuresplash, */*;q=0.5
x-flash-version: 10,1,53,64
Date: Thu, 23 Jun 2011 09:03:18 GMT
Authorization: AWS accesskey:signature
Content-Type: image/png
User-Agent: Mozilla/5.0 (Windows; U; en-US) AppleWebKit/531.9 (KHTML, like Gecko) AdobeAIR/2.0.2
Host: bucketname.s3.amazonaws.com
Content-Length: 0
Connection: Keep-Alive
Unsigned text:
POST\n
\n
image/png\n
Thu, 23 Jun 2011 09:03:18 GMT
/bucketname/btnOK.png?uploads
And I get the following error in response:
SignatureDoesNotMatch: The request signature we calculated does not match the signature you provided. Check your key and signing method.
Are some headers missing in the unsigned text? Maybe Referer, Accept etc. should be in the unsigned text?
I have using the Amazon S3 Signature Tester in JavaScript ( http://aws.amazon.com/code/199 ) and I'm getting the same unsigned text. Maybe the problem is in the encryption? I'm using as3crypto library. Here is my AS3 code for that:
private function generateSignature(datas:String, securityKey:String):String {
var sha:SHA1 = new SHA1();
var securityKeyArray:ByteArray = new ByteArray();
securityKeyArray.writeUTFBytes(escape(securityKey));
sha.hash(securityKeyArray);
var hmac:HMAC = new HMAC(sha);
var datasArray:ByteArray = new ByteArray();
datasArray.writeUTFBytes(escape(datas));
var signatureArray:ByteArray = new ByteArray();
signatureArray = hmac.compute(securityKeyArray, datasArray);
return Base64.encodeByteArray(signatureArray);
}
Please help! Thanks!
Related
I have an Azure function written in NodeJS where I'm attempting to cause an HTTP Redirect with a 302. The documentation is very sparse on what are valid entries in the response. As a result I've created an object with what I feel should be the correct entries to generate the redirect, but all I get is an XML response. Even items like the status code are shown in the XML rather than changing the real status code.
What am I doing wrong?
My Code:
module.exports = function(context, req){
var url = "https://www.google.com";
context.res = {
status: 302,
headers: {
Location: url
}
}
context.done();
}
This is the response I'm getting in the browser:
HTTP/1.1 200 OK
Cache-Control: no-cache
Pragma: no-cache
Content-Length: 1164
Content-Type: application/xml; charset=utf-8
Expires: -1
Server: Microsoft-IIS/8.0
X-AspNet-Version: 4.0.30319
X-Powered-By: ASP.NET
Date: Wed, 18 Jan 2017 00:54:20 GMT
Connection: close
<ArrayOfKeyValueOfstringanyType xmlns:i="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://schemas.microsoft.com/2003/10/Serialization/Arrays"><KeyValueOfstringanyType><Key>status</Key><Value xmlns:d3p1="http://www.w3.org/2001/XMLSchema" i:type="d3p1:int">302</Value></KeyValueOfstringanyType><KeyValueOfstringanyType><Key>headers</Key><Value i:type="ArrayOfKeyValueOfstringanyType"><KeyValueOfstringanyType><Key>Location</Key><Value xmlns:d5p1="http://www.w3.org/2001/XMLSchema" i:type="d5p1:string">https://www.google.com</Value></KeyValueOfstringanyType></Value></KeyValueOfstringanyType></ArrayOfKeyValueOfstringanyType>
The problem is that you're not defining the "body" in the response. This can be set to null, but it must be set for Azure functions to interpret it properly.
e.g. Update your code to:
module.exports = function(context, req){
var url = "https://www.google.com";
context.res = {
status: 302,
headers: {
Location: url
},
body : {}
}
context.done();
}
You will then get the desired response:
HTTP/1.1 302 Found
Cache-Control: no-cache
Pragma: no-cache
Content-Length: 0
Expires: -1
Location: https://www.google.com
Server: Microsoft-IIS/8.0
X-AspNet-Version: 4.0.30319
X-Powered-By: ASP.NET
Date: Wed, 18 Jan 2017 01:10:13 GMT
Connection: close
Edited 2/16/2017 - Using "null" for the body currently throws an error on Azure. As a result the answer was updated to use {} instead.
This is a bug with azure functions, see this content headers issue.
For now, a workaround is to remove any content related headers if the body of your response is null.
I am trying to make a call to the Emotion Api via JavaScript with in a PhoneGap app. I encoded the image into base64 and verified that the data can be decoded by one of the online tools. this is the code that i found on the web to use.
var apiKey = "e371fd4333ccad2"; //(you can get a free key on site this is modified for here)
//apiUrl: The base URL for the API. Find out what this is for other APIs via the API documentation
var apiUrl = "https://api.projectoxford.ai/emotion/v1.0/recognize";
"file" is the base64 string.
function CallAPI(file, apiUrl, apiKey)
{
// console.log("file=> " +file);
$.ajax({
url: apiUrl,
beforeSend: function (xhrObj) {
xhrObj.setRequestHeader("Content-Type", "application/octet-stream");
xhrObj.setRequestHeader("Ocp-Apim-Subscription-Key", apiKey);
},
type: "POST",
data: file,
processData: false
})
.done(function (response) {
console.log("in call api a");
ProcessResult(response);
})
.fail(function (error) {
console.log(error.getAllResponseHeaders())
});
}
function ProcessResult(response)
{
console.log("in processrult");
var data = JSON.stringify(response);
console.log(data);
}
I got back this:
Expires: -1
Access-Control-Allow-Origin: *
Pragma: no-cache
Cache-Control: no-cache
Content-Length: 60
Date: Fri, 01 Apr 2016 13:34:32 GMT
Content-Type: application/json; charset=utf-8
X-Powered-By: ASP.NET
So i tried their console test page.
https://dev.projectoxford.ai/docs/services/5639d931ca73072154c1ce89/operations/563b31ea778daf121cc3a5fa/console
I can put in an image like your "example.com/man.jpg" and it works great. but if i take the same image and have it encoded as a base 64 image all i get is "Bad Body" i have tried it both as content type "application/octet-stream" and "application/json" and get the same error. sample of the encoded looks like..and http request
POST https://api.projectoxford.ai/emotion/v1.0/recognize HTTP/1.1
Content-Type: application/octet-stream
Host: api.projectoxford.ai
Ocp-Apim-Subscription-Key: ••••••••••••••••••••••••••••••••
Content-Length: 129420
data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAASABIAAD/...
i get back:
Pragma: no-cache
Cache-Control: no-cache
Date: Fri, 01 Apr 2016 16:23:09 GMT
X-Powered-By: ASP.NET
Content-Length: 60
Content-Type: application/json; charset=utf-8
Expires: -1
{
"error": {
"code": "BadBody",
"message": "Invalid face image."
}
}
I am now not sure if you can send an image like this or not from Javascript. Can anyone tell me if my javascript is correct or if they can send an encoded base64 string image to the site.
thanks for your help
tim
This API does not accept data URIs for images. What you'll need to do is convert it to a binary blob. Though this answer is for a different Project Oxford API, you can apply the same technique.
When I am trying to update the a property (AvaliableQuantity) on an object and then update it via ODATA (using the oData v4 Client Code Generator). The problem is when I send the request (Fiddler output below) I get an error saying that "Only AvailableQuantity may be updated." Is there a way of specifying which of the properties can be updated (maybe via attributes?)
PATCH https://*****************/v1/DCQuantities(ProductID=33578709,DistributionCenterID=17) HTTP/1.1
OData-Version: 4.0
OData-MaxVersion: 4.0
Content-Type: application/json;odata.metadata=minimal
Accept: application/json;odata.metadata=minimal
Accept-Charset: UTF-8
User-Agent: Microsoft ADO.NET Data Services
Authorization: Bearer ************************
Host: **************
Content-Length: 153
Expect: 100-continue
{"#odata.type":"#ChannelAdvisor.RestApi.V1.Models.DCQuantity","AvailableQuantity":30,"DistributionCenterID":17,"ProductID":33578709,"ProfileID":22001149}
Below is the raw response from Fiddler
HTTP/1.1 400 Bad Request
Content-Length: 88
Content-Type: application/json; odata.metadata=minimal; charset=utf-8
Server: Microsoft-IIS/7.5
OData-Version: 4.0
X-ServerName: **********
Date: Wed, 16 Dec 2015 15:50:52 GMT
{
"error":{
"code":"","message":"Only AvailableQuantity may be updated."
}
}
I have been able to update properties on other objects so I know that the authentication (OAUTH2) and the basic classes are working.
Does anybody have any ideas on what I could try please?
Many thanks
Jonathan
OK, I have realised what I was doing wrong from this post (http://blogs.msdn.com/b/odatateam/archive/2014/04/10/client-property-tracking-for-patch.aspx). I was using code like this to get the object before changing it:
var product = target.Products.Expand("DCQuantities").Where(p => p.Sku == "JRSTEST1").First();
product.First().DCQuantities[0].AvailableQuantity = 42;
target.UpdateObject(product.DCQuantities[0]);
var result = target.SaveChanges();
What I needed to do was assign the result of the query to a DataServiceCollection<>() class which would then look after tracking what was actually changed and manage the whole update for me.
var product = new DataServiceCollection<Product>(target.Products.Expand("DCQuantities").Where(p => p.Sku == "JRSTEST1"));
product.First().DCQuantities[0].AvailableQuantity = 42;
var result = target.SaveChanges();
A simple server I'm working can serve images. When browsing to the image URL directly, Chrome offers to download the image, rather than just showing it in the browser. Why is that? Presumably it is something in the headers?
The relevant code is this:
tilestore.getTile(req.param("z"), req.param("x"), req.param("y"), function(err, tile) {
if (!err) {
res.send(tile);
} else {
res.send("Tile rendering error: " + err + "\n");
}
});
Do I need to add something to the headers? They are currently as follows:
HTTP/1.1 200 OK
Server: nginx/1.4.6 (Ubuntu)
Date: Mon, 01 Sep 2014 07:22:30 GMT
Content-Type: application/octet-stream
Content-Length: 37779
Connection: keep-alive
X-Powered-By: Express
ETag: W/"9393-1937584155"
Ok, it's easy. Just set the content-type:
if (!err) {
res.contentType('image/png');
res.send(tile);
} else {
res.send("Tile rendering error: " + err + "\n");
}
These images are always .png.
New headers:
HTTP/1.1 200 OK
Server: nginx/1.4.6 (Ubuntu)
Date: Mon, 01 Sep 2014 07:33:22 GMT
Content-Type: image/png
Content-Length: 37779
Connection: keep-alive
X-Powered-By: Express
ETag: W/"9393-1937584155"
Just ran into this same problem, and found that modifying the content type alone was not enough. This answer, attempting to do the opposite, provided the solution. I also needed to add a content-disposition header:
res.set("Content-Disposition", "inline;");
Along with setting the correct content type, this allowed me to display my image rather than downloading.
I had the same problem with svg image files and it turned out that I had to change
'content-type': 'image/svg'
to
'content-type': 'image/svg+xml'
I am trying to properly handle Accept headers in RESTful API in node.js/restify by using WrongAcceptError as follows.
var restify = require('restify')
; server = restify.createServer()
// Write some content as JSON together with appropriate HTTP headers.
function respond(status,response,contentType,content)
{ var json = JSON.stringify(content)
; response.writeHead(status,
{ 'Content-Type': contentType
, 'Content-Encoding': 'UTF-8'
, 'Content-Length': Buffer.byteLength(json,'utf-8')
})
; response.write(json)
; response.end()
}
server.get('/api',function(request,response,next)
{ var contentType = "application/vnd.me.org.api+json"
; var properContentType = request.accepts(contentType)
; if (properContentType!=contentType)
{ return next(new restify.WrongAcceptError("Only provides "+contentType)) }
respond(200,response,contentType,
{ "uri": "http://me.org/api"
, "users": "/users"
, "teams": "/teams"
})
; return next()
});
server.listen(8080, function(){});
which works fine if the client provides the right Accept header, or no header as seen here:
$ curl -is http://localhost:8080/api
HTTP/1.1 200 OK
Content-Type: application/vnd.me.org.api+json
Content-Encoding: UTF-8
Content-Length: 61
Date: Tue, 02 Apr 2013 10:19:45 GMT
Connection: keep-alive
{"uri":"http://me.org/api","users":"/users","teams":"/teams"}
The problem is that if the client do indeed provide a wrong Accept header, the server will not send the error message:
$ curl -is http://localhost:8080/api -H 'Accept: application/vnd.me.org.users+json'
HTTP/1.1 500 Internal Server Error
Date: Tue, 02 Apr 2013 10:27:23 GMT
Connection: keep-alive
Transfer-Encoding: chunked
because the client is not assumed to understand the error message, which is in JSON, as
seen by this:
$ curl -is http://localhost:8080/api -H 'Accept: application/json'
HTTP/1.1 406 Not Acceptable
Content-Type: application/json
Content-Length: 80
Date: Tue, 02 Apr 2013 10:30:28 GMT
Connection: keep-alive
{"code":"WrongAccept","message":"Only provides application/vnd.me.org.api+json"}
My question is therefore, how do I force restify to send back the right error status code and body, or am I doing things wrong?
The problem is actually that you're returning a JSON object with a content-type (application/vnd.me.org.api+json) that Restify doesn't know (and therefore, creates an error no formatter found).
You need to tell Restify how your responses should be formatted:
server = restify.createServer({
formatters : {
'*/*' : function(req, res, body) { // 'catch-all' formatter
if (body instanceof Error) { // see text
body = JSON.stringify({
code : body.body.code,
message : body.body.message
});
};
return body;
}
}
});
The body instanceof Error is also required, because it has to be converted to JSON before it can be sent back to the client.
The */* construction creates a 'catch-all' formatter, which is used for all mime-types that Restify can't handle itself (that list is application/javascript, application/json, text/plain and application/octet-stream). I can imagine that for certain cases the catch-all formatter could pose issues, but that depends on your exact setup.