I am creating an HTTP task that is triggering an endpoint on a Cloud Run service. The handler is being called from the queue, but I am unable to get the payload.
I have tried to log the headers, but it doesn't seem to contain content-type and I suspect that is why the app.use(bodyParser.raw({ type: "application/octet-stream" })); is failing.
These are all the request headers I'm receiving according to my Express handler:
{
"host": "my_service.a.run.app",
"x-cloudtasks-queuename": "notifications",
"x-cloudtasks-taskname": "36568403927752792701",
"x-cloudtasks-taskretrycount": "0",
"x-cloudtasks-taskexecutioncount": "0",
"x-cloudtasks-tasketa": "1640337087",
"authorization": "Bearer some_token",
"content-length": "193",
"user-agent": "Google-Cloud-Tasks",
"x-cloud-trace-context": "496573f34310f292ade89f566e7c8f40/11132544205299294705;o=1",
"traceparent": "00-496573f34310f292ade89f566e7c8f40-9a7ebdf8d332a1f1-01",
"x-forwarded-for": "35.187.132.21",
"x-forwarded-proto": "https",
"forwarded": "for=\"35.187.132.21\";proto=https",
"accept-encoding": "gzip, deflate, br"
}
This is currently what the handler looks like:
app.post("/send-notification", (req, res) => {
console.log(`req.headers: ${JSON.stringify(req.headers)}`);
console.log(`req.body: ${JSON.stringify(req.body)}`);
});
For body it prints {} but there should be a payload. I create it like this:
const task = {
httpRequest: {
httpMethod: "POST" as const,
url: def.url,
oidcToken: {
serviceAccountEmail,
},
body: Buffer.from(JSON.stringify(payload)).toString("base64"),
},
scheduleTime: {
seconds: 3 + Date.now() / 1000,
},
};
I have run out of ideas for things to try. What am I missing?
According to that example in the documentation, it's possible to add header to the request performed to Cloud Task.
You can add the content type in the header
const task = {
httpRequest: {
httpMethod: "POST" as const,
url: def.url,
headers: {
"Content-type": "application/json"
},
oidcToken: {
serviceAccountEmail,
},
body: Buffer.from(JSON.stringify(payload)).toString("base64"),
},
scheduleTime: {
seconds: 3 + Date.now() / 1000,
},
}
I am having trouble properly setting up csrf tokens in the authlink header.
const authLink = setContext((_, { headers }) => {
const token = localStorage.getItem(AUTH_TOKEN)
return {
"headers": {
'X-CSRFToken' : getCookie('csrftoken'),
"Authorization": token ? `JWT ${token}` : '',
...headers,
},
};
});
The request being sent looks ok from the browser devtools, as you can see at the bottom the csrf token looks right? I cleared my browser data to make sure it wasn't old, but I'm not sure if that's effective anyways.
accept: */*
Accept-Encoding: gzip, deflate, br
Accept-Language: en-US,en;q=0.9
Authorization
Connection: keep-alive
Content-Length: 505
content-type: application/json
Host: localhost:8000
Origin: http://localhost:3000
Referer: http://localhost:3000/
Sec-Fetch-Dest: empty
Sec-Fetch-Mode: cors
Sec-Fetch-Site: same-site
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/89.0.4389.90 Safari/537.36 Edg/89.0.774.63
X-CSRFToken: LsV83sz3Rb5RRIlNcRN3AgnniodwsSMpvXwMGquPGRbvoPpISfKv6MBEf86rVzVp
The error I get through the site is
CSRF verification failed. Request aborted
my django server shows
Forbidden (CSRF cookie not set.)
Have you tried to install corsheaders? or are you sure you have this function
function getCookie(name) {
var cookieValue = null;
if (document.cookie && document.cookie !== '') {
var cookies = document.cookie.split(';');
for (var i = 0; i < cookies.length; i++) {
var cookie = cookies[i].trim();
// Does this cookie string begin with the name we want?
if (cookie.substring(0, name.length + 1) === (name + '=')) {
cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
break;
}
}
}
return cookieValue;
}
I had same issue because x-csrftoken was not transmitted in the Request Headers
Here is the fix i have done
On my React code
import { ApolloClient, createHttpLink, InMemoryCache } from '#apollo/client';
import { setContext } from '#apollo/client/link/context';
import Cookie from "js-cookie";
const httpLink = createHttpLink({
uri: '/graphql/',
});
const authLink = setContext((_, { headers }) => {
return {
headers: {
...headers,
"x-csrftoken": Cookie.get("csrftoken")
}
}
});
const client = new ApolloClient({
link: authLink.concat(httpLink),
cache: new InMemoryCache()
});
I have this mostly working, unfortunately the file which starts off as a .png, becomes garbage by the time its on S3.
On the Angular side, I perform the upload with:
public uploadAsset(file: File, pointer: string):
{ name: string, url: string, isImg: boolean } {
const url: string = this.API_URL + '/posts' + pointer + '/assets' ;
// this will be the our resulting map
const status: { name: string, url: string, isImg: boolean } = {name: file.name, url: url + '/' + file.name, isImg: true};
// create a new multipart-form for the file
const formData: FormData = new FormData();
formData.append('file', file, file.name);
// create a http-post request and pass the form
// tell it to report the upload progress
const req = new HttpRequest('POST', url, formData, {
params: new HttpParams().set('fileName', file.name),
reportProgress: true
});
// create a new progress-subject for every file
const progress = new Subject<number>();
// send the http-request and subscribe for progress-updates
this.http.request(req).subscribe(event => {
if (event.type === HttpEventType.UploadProgress) {
// calculate the progress percentage
const percentDone = Math.round(100 * event.loaded / event.total);
// pass the percentage into the progress-stream
console.log(progress);
progress.next(percentDone);
} else if (event instanceof HttpResponse) {
// Close the progress-stream if we get an answer form the API
// The upload is complete
progress.complete();
}
});
return status;
}
The lambda that's processing it has the following code:
export const handler = async (event: any = {}) : Promise <any> => {
console.log(event);
const corsHeaders = {
'Access-Control-Allow-Origin': '*',
'Access-Control-Allow-Credentials': true,
};
try {
const method = event.httpMethod;
if (method === "GET") {
// GET handling left out for brevity
}
if (method === "POST") {
const path: string[] = event.path.split('/');
const s3Location = path[1] + '/' + path[2] + '/' + path[3];
const filename = event.queryStringParameters.fileName;
console.log(s3Location);
// Return error if we do not have a name
if (!s3Location) {
return {
statusCode: 400, headers: corsHeaders,
body: "name missing"
};
}
let base64data = Buffer.from(event.body, 'base64');
await S3.putObject({
ACL: "public-read",
Bucket: bucketName,
Key: s3Location + '/' + filename,
Body: base64data,
ContentType: contentTypeFromFile(filename)
}).promise();
return {
statusCode: 200, headers: corsHeaders,
body: JSON.stringify(event.queryStringParameters),
isBase64Encoded: false
};
}
if (method === "DELETE") {
// DELETE handling left out for brevity
}
// We got something besides a GET, POST, or DELETE
return {
statusCode: 400, headers: corsHeaders,
body: "We only accept GET, POST, and DELETE, not " + method
};
} catch(error) {
const body = error.stack || JSON.stringify(error, null, 2);
return {
statusCode: 400, headers: corsHeaders,
body: body
}
}
};
function assetFileNameFromEvent(event: any) {
const path: string[] = event.path.split('/');
return path[1] + '/' + path[2] + '/' + path[3] + '/' + path[4];
}
function contentTypeFromFile(locationKey: string): string {
const extension = locationKey.split('.')[1];
let contentType = 'image/';
switch(extension) {
case 'jpg': {
contentType += 'jpeg';
break;
}
case 'jpeg': {
contentType += 'jpeg';
break;
}
case 'gif': {
contentType += 'gif';
break;
}
case 'png': {
contentType += 'png';
break;
}
default: {
contentType += '*';
break;
}
}
return contentType;
}
The request is definitely getting to this Lambda, because I can see the console output in Cloudwatch, namely console.log(event); outputs:
2019-07-01T05:46:34.301Z 45035f0b-6c87-48dc-a83d-e02c4b4ff925 { resource: '/posts/{id}/assets',
path: '/posts/the-4-constraints-of-project-management/assets',
httpMethod: 'POST',
headers:
{ Accept: 'application/json, text/plain, */*',
'accept-encoding': 'gzip, deflate, br',
'Accept-Language': 'en-GB,en-US;q=0.9,en;q=0.8',
'CloudFront-Forwarded-Proto': 'https',
'CloudFront-Is-Desktop-Viewer': 'true',
'CloudFront-Is-Mobile-Viewer': 'false',
'CloudFront-Is-SmartTV-Viewer': 'false',
'CloudFront-Is-Tablet-Viewer': 'false',
'CloudFront-Viewer-Country': 'AU',
'content-type': 'multipart/form-data; boundary=----WebKitFormBoundary7AbJvvIOfZxOpNVc',
Host: 's4lr6s31m3.execute-api.ap-southeast-2.amazonaws.com',
origin: 'http://localhost:4200',
Referer: 'http://localhost:4200/post-edit/the-4-constraints-of-project-management',
'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.100 Safari/537.36',
Via: '2.0 d06686d3facabf043210ce048fc0afb2.cloudfront.net (CloudFront)',
'X-Amz-Cf-Id': 'sD6er2yXk2xTHwLio2dLusmxVlW4aBtL8XXfihnoc1cDdsPD95T7Ng==',
'X-Amzn-Trace-Id': 'Root=1-5d199e39-3fbc1d9861cda5c9e6016d19',
'X-Forwarded-For': '220.237.138.198, 54.239.202.94',
'X-Forwarded-Port': '443',
'X-Forwarded-Proto': 'https' },
multiValueHeaders:
{ Accept: [ 'application/json, text/plain, */*' ],
'accept-encoding': [ 'gzip, deflate, br' ],
'Accept-Language': [ 'en-GB,en-US;q=0.9,en;q=0.8' ],
'CloudFront-Forwarded-Proto': [ 'https' ],
'CloudFront-Is-Desktop-Viewer': [ 'true' ],
'CloudFront-Is-Mobile-Viewer': [ 'false' ],
'CloudFront-Is-SmartTV-Viewer': [ 'false' ],
'CloudFront-Is-Tablet-Viewer': [ 'false' ],
'CloudFront-Viewer-Country': [ 'AU' ],
'content-type':
[ 'multipart/form-data; boundary=----WebKitFormBoundary7AbJvvIOfZxOpNVc' ],
Host: [ 's4lr6s31m3.execute-api.ap-southeast-2.amazonaws.com' ],
origin: [ 'http://localhost:4200' ],
Referer:
[ 'http://localhost:4200/post-edit/the-4-constraints-of-project-management' ],
'User-Agent':
[ 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.100 Safari/537.36' ],
Via:
[ '2.0 d06686d3facabf043210ce048fc0afb2.cloudfront.net (CloudFront)' ],
'X-Amz-Cf-Id': [ 'sD6er2yXk2xTHwLio2dLusmxVlW4aBtL8XXfihnoc1cDdsPD95T7Ng==' ],
'X-Amzn-Trace-Id': [ 'Root=1-5d199e39-3fbc1d9861cda5c9e6016d19' ],
'X-Forwarded-For': [ '220.237.138.198, 54.239.202.94' ],
'X-Forwarded-Port': [ '443' ],
'X-Forwarded-Proto': [ 'https' ] },
queryStringParameters: { fileName: '4constraints.png' },
multiValueQueryStringParameters: { fileName: [ '4constraints.png' ] },
pathParameters: { id: 'the-4-constraints-of-project-management' },
stageVariables: null,
requestContext:
{ resourceId: '1l0n12',
resourcePath: '/posts/{id}/assets',
httpMethod: 'POST',
extendedRequestId: 'cIWpCEhaSwMF6MA=',
requestTime: '01/Jul/2019:05:46:33 +0000',
path: '/prod/posts/the-4-constraints-of-project-management/assets',
accountId: '499908792600',
protocol: 'HTTP/1.1',
stage: 'prod',
domainPrefix: 's4lr6s31m3',
requestTimeEpoch: 1561959993894,
requestId: '95662d4b-9bc3-11e9-8a59-31b56e75ceeb',
identity:
{ cognitoIdentityPoolId: null,
accountId: null,
cognitoIdentityId: null,
caller: null,
sourceIp: '220.237.138.198',
principalOrgId: null,
accessKey: null,
cognitoAuthenticationType: null,
cognitoAuthenticationProvider: null,
userArn: null,
userAgent: 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.100 Safari/537.36',
user: null },
domainName: 's4lr6s31m3.execute-api.ap-southeast-2.amazonaws.com',
apiId: 's4lr6s31m3' },
body: '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',
isBase64Encoded: true }
The body even looks base64 encoded, which is, according to what I have read elsewhere, is a good thing. However when I look in S3, or perform a GET, I end up with a mangled file (no image). Although the file size is the same (or at least very similar).
I'm hoping I'm only missing something small, perhaps some simple conversion that I have to make. Can anyone tell me what that might be?
I have below get request. But its giving 401 Unauthorized error.
var headers = new Headers();
headers.append('Content-Type': 'application/json;charset=UTF-8');
this.http.get(urgentPostURL + encodeURIComponent(this.urgentpost.comment))
.map((res:Response) => res.json())
.subscribe(data => {
this.result = data;
console.log('UrgentPost Result : ' + this.result.Success);
if (this.result.Success == true) {
console.log("SUCESSS");
} else {
console.log("FAILED");
}
},err => console.error(err),() => console.log('done'));
What I'm doing wrong here?
Edited
After updated to the following code I'm still getting 401:
var headers = new Headers();
headers.append('Content-Type': 'application/json;charset=UTF-8');
headers.append('Authorization', 'Basic ' + btoa("123" + ':' + "123"));
this.http.get(urgentPostURL + encodeURIComponent(this.urgentpost.comment), { headers: headers })
.map((res:Response) => res.json())
.subscribe(data => {
General:
Request Method:GET
Status Code:401 Unauthorized
Response headers:
Access-Control-Allow-Origin:*
Cache-Control:no-cache
Content-Length:0
Date:Tue, 23 Feb 2016 11:26:17 GMT
Expires:-1
Pragma:no-cache
Server:Microsoft-IIS/8.0
Set-Cookie:ARRAffinity=6e6dd0608a0902ef40a800ab07ee37397d7b6cfbd85cf3dea254a7115d365bc1;Path=/;Domain=sd.sddd.net
WWW-Authenticate:Basic
X-AspNet-Version:4.0.30319
X-Powered-By:ASP.NET
Request headers:
Accept:*/*
Accept-Encoding:gzip, deflate, sdch
Accept-Language:en-US,en;q=0.8
Authorization:Basic MDAwMDAwMDoxMjM0NTY3OA==
Connection:keep-alive
Content-Type:application/json;charset=UTF-8
Host:sd.sddd.net
Origin:http://localhost:8100
Referer:http://localhost:8100/
User-Agent:Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/48.0.2564.109 Safari/537.36
I seems that the server requires authentication. You didn't define the Authorization header for your call.
Here is a sample for an HTTP basic authentication:
var headers = new Headers();
headers.append('Content-Type': 'application/json;charset=UTF-8');
headers.append('Authorizcation', 'Basic '+btoa(username + ':' + password));
this.http.get(urgentPostURL + encodeURIComponent(
this.urgentpost.comment,
{ headers: headers })
.map((res:Response) => res.json())
(...)
Don't forget to specify your headers for your request and to import the Headers class.
I'm trying to look for a resource in the dom, in order to that I'm following each link of the current page.
The problem is that the first time works perfectly well, but when I start to follow the links I receive "cookies are not enabled".
I call the script like this: casperjs --cookies-file=/tmp/mycookies.txt script.js
Here is the script:
var casper = require('casper').create({
logLevel: "debug", // Only "info" level messages will be logged
verbose:true,
onError: function(self, m) { // Any "error" level message will be written
console.log('FATAL:' + m); // on the console output and PhantomJS will
self.exit(); // terminate
},
pageSettings: {
javascriptEnabled: true,
loadImages: false, // The WebPage instance used by Casper will
loadPlugins: false, // use these settings
userAgent: 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_7_5) AppleWebKit/537.4 (KHTML, like Gecko) Chrome/22.0.1229.94 Safari/537.4'
}
});
var fs = require('fs');
casper.userAgent('Mozilla/5.0 (Macintosh; Intel Mac OS X 10_7_5) AppleWebKit/537.4 (KHTML, like Gecko) Chrome/22.0.1229.94 Safari/537.4');
phantom.cookiesEnabled = true;
var x = require('casper').selectXPath;
function getLinks() {
var links = document.querySelectorAll('a');
return Array.prototype.map.call(links, function(e) {
return e.getAttribute('href')
});
}
function followLinks(links) {
casper.each(links, function(self, link) {
self.thenOpen(link, function() {
fs.write("pages/" + link+ ".html", this.getHTML(), 'w'); //for debugging
if (!lookFor(x('//input[#name="Export"]'))) {
var links = getLinks();
followLinks(links);
}
});
});
}
casper.start('http://www.url.com', function() {
this.fill('form#formAuth', {
login: 'user#url.com',
password: 'apass'
}, true);
});
casper.then(function() {
links = links.concat(this.evaluate(getLinks));
followLinks(links);
});
casper.run(function() {
this.exit();
});
The problem was that one of the links is the Logout Link :D. That's why suddenly I got the error