I was previously able to send curl messages to
http://fcm.googleapis.com/fcm/send
However now I get
403:Forbidden Error
However, the same curl script works if I change http to https.
This restriction seems to have been put in place yesterday.
My source of messages is an arduino which can only handle HTTP and not HTTPS.
Does anybody know if I can still send HTTP requests to FCM via another route?
Ok, I now have a workaround solution for my Arduino ESP Project to use HTTPS with Google Firebase Cloud Messaging.
i thought I would share it for others stuck in the same rut.
In a nutshell, I created a free PHP website, which offered curl functionality, and scripted an HTTP API to accept HTTP requests and forward them onto Google FCM using an HTTPS Connection.
Here are my solution steps:
Sign up to free account aon https://www.000webhost.com
Create/Manage a free subdomain website eg "yourname" (www.yourname.000webhostapp.com)
Dashboard -> Tools -> FileManager -> Upload Files
in your "public_html" folder create a new file named "api.php"
Paste the PHP code below into this file, and Save & Close
Replace your Arduino old code http references for "http://fcm.googleapis.com/fcm/send"
with "http://yourname.000webhostapp.com/api.php"
Job done!
<?php
// This API allows Arduino to send HTTPS FCM messages
// Takes raw data from the incoming HTTP request
$json = file_get_contents('php://input');
$curl = curl_init();
curl_setopt($curl, CURLOPT_URL, 'https://fcm.googleapis.com/fcm/send');
curl_setopt($curl, CURLOPT_POST, 1);
curl_setopt($curl, CURLOPT_POSTFIELDS, $json);
// build the outgoing headers
$hdr_out = array();
$hdr_out[] = 'Content-Type: application/json';
// read incoming header to extract just the auth key
foreach (getallheaders() as $name => $value) {
//echo "$name: $value\n";
if (strtoupper($name) == "AUTHORIZATION") {
$hdr_out[] = 'Authorization: '. $value;
}
}
curl_setopt($curl, CURLOPT_HTTPHEADER, $hdr_out);
$result = curl_exec($curl);
if ($result) {
$response_code= curl_getinfo($curl, CURLINFO_RESPONSE_CODE);
curl_close($curl);
http_response_code($response_code);
}
else {
echo "API Failure";
http_response_code(500);
}
?>
Its my first attempt at writing PHP code, so feel free to suggest any improvements.
I also have an Arduino project (ESP8266 based) that is also sending http (not https) posts to http://fcm.googleapis.com/fcm/send. that has also stopped working.
I was able to confirm via Postman that requests sent to http://fcm.googleapis.com/fcm/send fail with a 403 (Forbidden) response.
I was able to get something working again by adding a fingerprint to the call to the begin method.
http.begin("https://fcm.googleapis.com/fcm/send", "F6:84:98:95:E5:6B:AC:EC:17:79:74:BF:1A:4B:E0:7E:FA:C8:EC:E9");
I was able to find the fingerprint using this site https://www.grc.com/fingerprints.htm
My actual app however is crashing with the the above update, so I still need to dig into this some more. I think there is a bug in the HttpClient that has already been fixed and I am just not picking it up.
Update
The issue with my full Arduino app crashing was due to the https request using too much memory (esp8266's don't have a lot of memory). I looked at a few options that could reduce the memory requirements, but ultimately I decided to go with a similar, but slightly different approach than what Solara07 posted.
Since I already had a raspberry pi running on my network I decided to use that as a proxy.
I installed trafficserver on the raspberry pi and added the following two lines to the /etc/trafficserver/remap.config
map http://192.168.86.77/fcm/send https://fcm.googleapis.com/fcm/send
reverse_map https://fcm.googleapis.com/fcm/send http://192.168.86.77/fcm/send
The required change to my arduino code was the following:
Change:
http_.begin("http://fcm.googleapis.com/fcm/send");
To:
http_.begin("192.168.86.77", 8080, "http://192.168.86.77/fcm/send");
where http_ is the instance of the HTTPClient
and 192.168.86.77 is the private internal address of my raspberry pi
More details and an answer to some problems I had implementing this can be found here.
Set http (http://fcm.googleapis.com/fcm/send) by https (https://fcm.googleapis.com/fcm/send) on API URL.
Related
I'm trying to make some Rest-API Calls to the Google Calendar API from my Application to show some Calendar Data and I'm slowly but surely a little in despair.
I've activated the API, created Credentials and downloaded the client-secret Json File.
For testing I used Postman to send an example Request to the api like https://www.googleapis.com/calendar/v3/calendars/{calendar-ID}/acl
Because there was no Access Token to in the json file I used "Get new Access Token", entered all the Data from the json and got a Key. But if I use this Key for sending a Request with oAuth2 Authorization and that example API-Call i get a back a 401.
I played around with this for hours without any success. I'm not very experienced with this kind of Authorization and surely missing a point here.
Actually I just want to make some cUrls from my php-script to get some Calendar Data. Maybe someone could describe the steps that are nessecary to get this done.
thank you in advance. :)
The credentials file that you downloaded from google identifies your application to google. It does not give you direct access to an api.
In order to access a google api containing private user data you need to be authenticated using OAuth2 to gain consent of the resource owner to accesses their data.
These links may help you set up postman using the client id and client secret you have from Google developer console.
Google calendar oauth2
Google Oauth2
Postman oauth2
One problem left. Using the access token to get Data via Postman works in between. Also using the refresh-token to get a new acces token.
But in my Curl, when doing the api-request, i still get a 401 back. Refreshing the access token via curl works pretty well, but the actual api-call for getting data seems still not to be on point.
$oCurl = curl_init();
curl_setopt($oCurl, CURLOPT_HTTPHEADER, array(
'Authorization' => 'Bearer '.$token,
));
curl_setopt($oCurl, CURLOPT_CONNECTTIMEOUT, 5);
curl_setopt($oCurl, CURLOPT_TIMEOUT, 30);
curl_setopt($oCurl, CURLOPT_RETURNTRANSFER, true);
curl_setopt($oCurl, CURLOPT_SSL_VERIFYPEER, true);
curl_setopt($oCurl, CURLOPT_SSL_VERIFYHOST, 2);
curl_setopt($oCurl, CURLOPT_URL, $url);
$response = curl_exec($oCurl);
$list = json_decode($response );
so Response is still
[code] => 401
[message] => Login Required
maybe someone has a clue whats wrong here? :)
€ okay, changing 'Authorization' => 'Bearer '.$token, to 'Authorization: Bearer '.$token, made it.
Thanks for your help
I'm using Guzzle 3.8.1 via Misd GuzzleBundle in Symfony (2.4.*). Both in my development and testing environments (both have the api endpoints on the same server), I am able to fire Async post requests with success.
In my production environment my endpoint is on the same server but accessed via a separate subdomain using apache vhosts. I am using Basic Authentication, at the moment it is via http (eventually https). However my Async requests are returning 200 status codes but I'm not getting POST data stored on my remote server for these requests.
$this->client->addSubscriber(new AsyncPlugin());
$request = $this->client->post(
'statements',
array(
'Accept' => 'application/json',
'Content-Type' => 'application/json',
'X-Experience-API-Version' => '1.0.1'
),
json_encode($statement)
)->setAuth($this->authuname,$this->authpass);
$response = $request->send();
However if I remove the $this->client->addSubscriber(new AsyncPlugin()); and fire the same post request synchronously then my POST data is stored on the remote server.
I am using the logging functionality in the misd guzzle bundle. For the asynch request log I can see the json data in the request, as it doesn't wait for the response all I get is:
<<<<<<< HTTP/1.1 200 OK X-Guzzle-Async: Did not wait for the response --------
I have checked curl and it is enabled and same set up in dev than it is in production. The only issue is that async isn't working on the production server. I am using apache 2.4.6 on Windows Server 2008.
Has anyone else had similiar issues. Is there anyway to log the responses somewhere even though this is done asynchronously. I have logging set up in my vhosts, but as it's getting a 200 I'm not seeing anything there.
Hope someone can advise, let me know if you need any further information.
Kind regards,
Paul Pounder
I checked out this link here on SO: Dealing with HTTP content in HTTPS pages
I tried this regarding open protocols from here: http://benpowell.org/https-and-http-the-protocol-less-or-protocol-relative-urls/
But I have only one call to an HTTP url for openweathermap which does not serve up it's content via HTTPS, unless you pay them 500/mo. Can't do it.
So, I need to find a way to bring in the HTTP content for OpenWeatherMap and not generate the "mixed content" error message on "any" browser.
Here's the API call for OWM: http://api.openweathermap.org/data/2.5/weather?lat=32.22&lon=-100.50&APPID=c6fdcf2d49a0bba3e14f310bd3d5cdc2
Any thoughts, anyone?
Thanks, in advance.
Stumbled upon this thread while trying to get my application hosted on heroku while using the Open Weather Map API.
Put this in front of the url:
https://cors-anywhere.herokuapp.com/
so that the url becomes
https://cors-anywhere.herokuapp.com/http://api.openweathermap.org/data/2.5/forecast?
appid=${API_KEY}
Check your application again and note that the openweather url is http again (the way it was originally)! This solution worked for me, although the CORS solution may not last forever.
I was able to get the api to load on my site that enforces https with a little bit of php.
Basically, I curl the http site and store the results on a page on my domain which is https so it works perfect for me.
I wrote a little function to do the work for me
<?php
#Defining the basic cURL function
function curl($url) {
$ch = curl_init(); // Initialising cURL
#Setting cURL's URL option with the $url variable passed into the function
curl_setopt($ch, CURLOPT_URL, $url);
#Setting cURL's option to return the webpage data
curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE);
#Executing the cURL request and assigning the returned data to the $data variable
$data = curl_exec($ch);
#Closing cURL
curl_close($ch);
#Returning the data from the function
return $data;
}
echo $scraped_website = curl("http://www.example.com");
#I use http://api.openweathermap.org/data//2.5/weather?q=Saint+Louis%2C+MO&units=imperial&lang=nl&APPID=b923732c614593659457d8f33fb0d6fd&cnt=6 instead of "http://www.example.com"
?>
#Full snippet
<?php
// Defining the basic cURL function
function curl($url) {
$ch = curl_init(); // Initialising cURL
curl_setopt($ch, CURLOPT_URL, $url); // Setting cURL's URL option with the $url variable passed into the function
curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE); // Setting cURL's option to return the webpage data
$data = curl_exec($ch); // Executing the cURL request and assigning the returned data to the $data variable
curl_close($ch); // Closing cURL
return $data; // Returning the data from the function
}
echo $scraped_website = curl("http://www.example.com");
?>
enter code here
Since forecast.io changed into Dark Sky and they don't allow CORS, thus forcing you to implement a server-side application, I looked for a different solution suitable for a small front-end project.
I found apixu.com, which seems to be much better suited for a simple purpose like mine: FreeCodeCamp project.
They provide both, http and https calls. You get 5000 calls per month for free.
Are there headers you can send with a HTTP request that tell the web server to send you only headers in response and no body content?
I am using cURL to make such requests, but technically I assume it should be possible with simple header being sent as part of the request.
For example, there exists a 304 Not Modified HTTP Response Code. When you make a request to the server with your cache tag or datetime information, then the server can detect that and only return headers as a response that tell the user agent to use their cache as the response. This means that the response from the server is very, very small when it comes to bandwidth.
But is there a header you can send to servers that make the server only return a header and no body content?
The idea here is to make HTTP requests that otherwise might return large amount of data, very small. Such as an API call that would return JSON data or a log, when in fact the only thing user agent is interested in is making sure that the request went through and nothing else. This is in order to minimize the bandwidth to and from the server in cases where the body might exist, but is not necessary in any way in context to what the user agent is doing.
While it would be possible to design an API that listens to a specific custom header or whatnot, I'd rather not go this way unless I have to. But I've been unable to find if there is a standardized way to make a HTTP request that tells server not to send any body content?
If the server supports it, there is the HEAD action (as opposed to GET or POST). That tells the server to only send the headers, and no body.
The HEAD method is identical to GET except that the server MUST NOT
return a message-body in the response.
You're looking for the verb HEAD. If you're using CURL with PHP, this will do the trick:
curl_setopt( $c, CURLOPT_RETURNTRANSFER, true );
curl_setopt( $c, CURLOPT_CUSTOMREQUEST, 'HEAD' );
curl_setopt( $c, CURLOPT_HEADER, 1 );
curl_setopt( $c, CURLOPT_NOBODY, true );
If you are using PHP though (and it may very well also count in different situations), the script will continue to run until any output is sent (the note under REQUEST_METHOD). So if you're worried about the server stress, you might require something else if that fits.
To me it looks like you're more looking for a 'ping', so why not simply request a file that does nothing but return an OK of some kind, perhaps even just the HTTP 200 OK (i.e. an empty file)?
I need to post a string from a .NET site to a Classic ASP site which are hosted on the same server (different virtual directories).
https: //example.com/DOTNETSite/Sender.aspx
to
https: //example.com/ClassicASP/SomeFolder/Target.asp
Target.asp page has 3 ways to handle incoming data:
Form Post
Query String
Headers
I cant pass my data in query string. so that option is out. I am trying the Form post method by building a form on the server side and spitting out javascript code to do a form.submit(). But this is causing a internet explorer to throw a Security Alert for the user. We want to avoid this. Please let us know what is the best way to overcome this situation. Thanks a ton.
Right now you are doing:
your server ----> your client/browser ----> their server
Instead you should use:
your server ----> your client/browser ----> your server ----> their server
That is (if it wasn't clear enough), make it send the form to your own server.
When your server receives the form, it should send it to the target server.
On a basic level, this works. However, you may get issues if the user is supposed to be logged in on the 2nd server etc.
I'll try to illustrate an example in PHP:
File: form.html
<form action="send.php" method="post">
....
</form>
File: send.php
<?php
$url='https://example.com/ClassicASP/SomeFolder/Target.asp';
// create new cur connection
$ch=curl_init();
// tell curl target url
curl_setopt($ch, CURLOPT_URL, $url);
// tell curl we will be sending via POST
curl_setopt($ch, CURLOPT_POST, true);
// tell it not to validate ssl cert
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
// tell it where to get POST variables from
curl_setopt($ch, CURLOPT_POSTFIELDS, $_POST);
// make the connection
curl_exec($ch);
// close connection
curl_close($ch);
?>