Examine raw HTTP request from UrlFetchApp.fetch - google-apps-script

I am working on something to interact with Amazon's REST API, but I keep getting an error in my response that points to a mal-formed request. I don't see any errors in the code (the parameter that it says is missing is clearly there), so I want to see the raw request that is being sent.
I don't see any available method that will let me do this. Maybe a server that will just include my request as its response?

Create your own endpoint that will echo to the screen your request. For example, to echo a GET request, send it to a script like this (that's been Publish > Deploy as web app):
function doGet(e) {
var test = 'Echo at ' + new Date() + '\n' + e.queryString;
return ContentService.createTextOutput(test);
}

A little late to the game (10 years) but you can now do this:
const requestResult = UrlFetchApp.getRequest(url, options);
Run it in debug mode and break after this executes to examine requestResult.
See: https://developers.google.com/apps-script/reference/url-fetch/url-fetch-app#getrequesturl,-params for an official description and a full explanation of the properties for the options parameter.

Related

Google App Script UrlFetchApp error need ivs

I tried to login my account by using UrlFetchApp, when I ran script manually, everything worked well. But when I set trigger to run automatically, it returned "error_need_ivs". I have no idea what it is and how to fix. please help me. Below is my code
function login() {
var data = {
'username':'username',
'password_hash':'password',
}
var option = {
muteHttpExceptions: true,
"method" : "POST",
"payload" : data,
}
var url = 'my url'
var res = JSON.parse(UrlFetchApp.fetch(url,option).getContentText());
Logger.log(res) //returned error_need_ivs when I set trigger but worked well when I ran script manually
}
UPDATE : This picture show the result after scripting executed by trigger
From the new screenshot shared I can see no Exceptions were thrown, which means the error logged error_need_ivs certainly comes from the response of the HTTP request rather than an issue with Apps Scripts.
Regarding why it works when calling the affected function manually and why it doesn't worked when invoking it via timed-trigger, I believe what #Tanaike suggested to make sense, maybe the affected endpoint is not prepared to receive IPv6 requests or require more data when doing so.
I'd suggest checking the documentation for the endpoint you are making the request for to help identify what might be causing this behavior.
Alternatively, I'd also suggest to report it as an Issue on IssueTracker using this template. Make sure to include a full reproducible scenario when reporting it (including a working endpoint).

GAS Wialon Local Remote API: Retrieve login data

Good day,
I have a Wialon Local server (GPS monitoring system) and am planning to update a shared Google sheet using time-driven installable triggers.
As per the Wialon documentation, I am able to get the desired response when entering my API call in a browser.
However, in GAS, I am getting the below error when trying to retrieve data from the response.
API Call:
let apiURL = `http://my.tracking.site.come/wialon/ajax.html?svc=token/login&params={"token":"5dce19710a5e26ab8b7b898XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXFCEED7DC03BC48FF5F8"}`
console.log(apiURL) // This URL works in a web browser as expected
var resText = UrlFetchApp.fetch(apiURL).getContentText() // error is raised on this line
console.log(resText)
The error:
11:48:27 AM Error
Exception: Invalid argument: http://my.tracking.site.come/wialon/ajax.html?svc=token/login&params={"token":"5dce19710a5e26ab8b7b898XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXFCEED7DC03BC48FF5F8"}
wialonLogin # wialon.gs:20
Kindly advise what I am doing wrong here as I have very little experience with both GAS and Wialon Remote API ... will appreciate any assitance.
Thanks.
Solution is to encode the URL.
let apiURL = `http://my.tracking.site.come/wialon/ajax.html?svc=token/login&params={"token":"5dce19710a5e26ab8b7b898XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXFCEED7DC03BC48FF5F8"}`
console.log(apiURL) // This URL works in a web browser as expected
var urlEncoded = encodeURI(apiURL);
var resText = UrlFetchApp.fetch(urlEncoded).getContentText() // error is raised on this line
console.log(resText)

Downloading file from Google Drive by using Google Picker

I'm trying to build a webpage on which user can select an image from Google Drive by using Google Picker and download selected files to my server by using PHP script.
I have managed to setup the Picker, and i get fileIDs but when i pass this IDs to my backend and try GET method i get an authentication error.
I have spent 2 days working on this and researching, but more I read google official documentation the more confused I am.
Can someone tell me, or link me the example how implement this? Is it possible to somehow pass the oAuthv2 token from the GooglePicker to my PHP backend and then use that token with the GET request?
Thank you very much in advance !
edit:
here is the error that im geting when i try GET https://www.googleapis.com/drive/v2/files/SOME_FILE_ID
{
"error": {
"errors": [
{
"domain": "usageLimits",
"reason": "dailyLimitExceededUnreg",
"message": "Daily Limit for Unauthenticated Use Exceeded. Continued use requires signup.",
"extendedHelp": "https://code.google.com/apis/console"
}
],
"code": 403,
"message": "Daily Limit for Unauthenticated Use Exceeded. Continued use requires signup."
}
Before you call the GET, you must set an Authorisation-Header containing an up to date access token.
If you want to do this manually, the steps are:-
Request permission using your app-id/client-id and scopes. This will return to you an authorization code.
Use the authorization code to request a refresh token and an access token
Store the refresh token for future use
Set the access token in an http header Authorization (something like Authorization: Bearer ya29.AHES6ZR3HQa9trJM_IQcgNlM0SI4FvLQFiQfcAZCWLobfpjqtGlT6A)
Issue your GET
You can see the whole process in action by clicking around at https://developers.google.com/oauthplayground/
Alternatively, if your client app already has an access token, you could send that to your server alongside the file ID and your server can simply set that directly into the Authorization header.
There are PHP libraries you can use instead, eg. go to https://developers.google.com/drive/v2/reference/files/insert and scroll down to see the PHP samples. It's entirely your choice whether you build the URLs by hand or use the libraries. The big disadvantage to the libraries is that if something goes wrong, you really need to understand and trace the http anyway to see what's going on, so might as well get to learn and love them from day one.
The message "Daily Limit for Unauthenticated Use Exceeded" seems to confuse first timers (me included). It's the "Unauthenticated Use" which is the important part, meaning you haven't set the Authorization header. Google APIs have a daily quota for unauthorized use (stuff like URL shortener). In the case of Drive, that quota is ZERO, hence the error.
#pinoyyid said everything as it is, and inspired by him, here is the actual solution I came up with:
If you want to download a file, you need two variables - oAuthToken and fileId
oAuthToken you get from JS client side when user authenticates.
If you use the example from google docs (https://developers.google.com/picker/docs/), the function looks like this:
function handleAuthResult(authResult) {
if (authResult && !authResult.error) {
oauthToken = authResult.access_token;
oauthToken; // <-- THIS IS THE Bearer token
createPicker();
}
}
fileId you get from when user picks a file. Again, a modified example from google docs:
function pickerCallback(data) {
if (data[google.picker.Response.ACTION] == google.picker.Action.PICKED) {
var doc = data[google.picker.Response.DOCUMENTS][0];
alert('You picked fileId: ' + doc[google.picker.Document.ID]);
}
}
Probably you will pass these data as a form request, or through ajax. Simple cURL call from backend to download the file:
$oAuthToken = 'ya29.XXXXXXXXXXXXXXXXXXXXXXXXX-XXXXXXXXX-XXXXXXX-XXXXXX-X-XXXXXXXXXXXX-XXXX';
$fileId = '0B4zzcXXXXXXXXXXXXXXXXXXXXXX';
$getUrl = 'https://www.googleapis.com/drive/v2/files/' . $fileId . '?alt=media';
$authHeader = 'Authorization: Bearer ' . $oAuthToken ;
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $getUrl);
curl_setopt($ch, CURLOPT_HTTPHEADER, [
$authHeader ,
]);
$data = curl_exec($ch);
$error = curl_error($ch);
curl_close($ch);
file_put_contents("destination-file.jpg", $data);
Docs about file download: https://developers.google.com/drive/web/manage-downloads
You store the refresh token in the database. When an API call is checked whether the current token is still valid. If not, a new access-token is retrieved by using the refresh-token

Box Server file upload error while using a QT application coded using the new OAuth2 API

I have been working on a Box App using the API v2 for the past few days and have successfully authenticated using OAuth2.
My app retrieves the access token successfully and I'm also able to access my Box account using the access token, however an upload of a file fails with a response of 299.
The html response I see from Box after posting an upload request has the following message
"Sorry, we can't access that page."
Your Box account may be temporarily unavailable. We're working on resolving the issue and should be back up soon."
I take it all 2xx errors mean that the request has been accepted but the Box server cannot handle it.
Given below is a snippet of my code used to post the file.
Any tips on what could be wrong is appreciated
I am following instructions from
http://developers.box.com/get-started/#uploading-and-downloading
QUrl requrl = QUrl("https://www.box.com/api/2.0/files/content");
std::string token = m_acc_token;
QString hdrval = "Bearer "+QString(token.c_str());
QNetworkRequest qnr(requrl);
qnr.setRawHeader("Authorization",hdrval.toUtf8());
QString boundary;
boundary = "---------7d935033608e2";
QByteArray data;
data.append("file=#btest.txt");
data.append(boundary);
data.append("folder_id=0");
data.append(boundary);
qnr.setHeader(QNetworkRequest::ContentTypeHeader,"multipart/form-data; boundary=---------7d935033608e2");
qnr.setHeader(QNetworkRequest::ContentLengthHeader,data.size());
QNetworkReply* areply = NULL;
areply = m_networkManager->post(qnr,data);
you can implement it like
QHttpMultiPart *multiPart = new QHttpMultiPart(QHttpMultiPart::FormDataType);
QHttpPart headerPart;
headerPart.setHeader(QNetworkRequest::ContentDispositionHeader, QVariant("form-data; name=\"parent_id\" \" "));
headerPart.setBody(QString(aParentFolderId).toLatin1());
QHttpPart textPartData;
textPartData.setHeader(QNetworkRequest::ContentDispositionHeader, QVariant("form-data; filename=\"filename\" \" "));
textPartData.setBodyDevice(&File); //file must be open.
File.setParent(multiPart);
multiPart->append(headerPart);
multiPart->append(textPartData);
QNetworkRequest networkReq;
networkReq.setUrl(QUrl("https://upload.box.com/api/2.0/files/content"));
networkReq.setRawHeader("Authorization", "Bearer " + AccessToken.toLatin1());
networkReply = mNetworkAccessManager.post(networkReq, multiPart);
multiPart->setParent(networkReply);
The curl call in the Box API documentation can't be translated directly to code as you have done. the file=#btest.txt line on the command line puts the contents of file btest.text as the value of the parameter file.
Additionally, your multipart boundaries are malformed: they must end in \r\n; one must be present at the start of the multipart body, and another boundary with a slightly different format must be present as a final boundary. If you are interested in manually implementing the multipart form data, I'd recommend reading RFC 1876.
The Box API will return a 500 response if it is sent a malformed multipart POST body.
I'd recommend using QHttpMultiPart, for multipart form uploads, which is part of the Qt framework.

Unexpected Error Google Apps Script Fetch

I get an "Unexpected Error" from the following function:
function getBomgarFeedbackXML(){
var url = "https://help.tradingtechnologies.com/api/reporting.ns?" +
"username=xxxxxx&password=xxxxxx&generate_report=SupportCustExitSurvey&" +
"start_date=2000-01-01&duration=0&report_type=rep&id=all";
var response = UrlFetchApp.fetch(url).getContentText();
Logger.log(response);
return(Xml.parse(response, true));
}
The line that causes the error is:
var response = UrlFetchApp.fetch(url).getContentText();
I am able to fetch the URL programatically using other scripting languages, such as python
I have tried fetching the URL in my browser which I was able to do successfully
I can fetch "http://www.google.com" from Google apps script successfully
I get the following warning when navigating to the URL in chrome, could this be related to the issue ?
Any help is appreciated
Thanks
The last bit with the untrusted certs is the big clue here. Seems like the SSL cert associated with 'help.tradingtechnologies.com'is not valid or signed by a trusted CA per the Google Data Centers (from where the UrlFetch calls originate).
To work around this try this line of code instead of your UrlFetch call. Note the additional option for validateHttpsCertificates documented here.
var response = UrlFetchApp.fetch(url, {'validateHttpsCertificates':false}).getContentText();