Headers and POST data disappear when using AJAX and mod_rewrite - javascript

I have an instance of Apache 2.2.21 on Windows 7 running at http://localhost that uses mod_rewrite to redirect requests beginning with /backend to http://localhost:8080. The server at http://localhost:8080 is in turn a CherryPy 3.2.0 server that is designed to accept POSTed JSON messages and respond with JSON messages.
My problem is that when I try to POST to http://localhost/backend using AJAX the CherryPy server ends up seeing a message with no request headers and no attached JSON data. It thus returns a 400 BAD REQUEST error. But I also have applications built in Excel and .NET that send similar messages to http://localhost/backend with no problems. Also, I've tried setting up a page at http://localhost/route (that uses Django) which passes the AJAX POST along to http://localhost:8080; this works perfectly.
My question then is why the AJAX POST to `http://localhost/backend' is not working. Perhaps this is related to AJAX security?
Example JavaScript using jQuery would be something like
$.post(
"/backend",
JSON.stringify({"type": "getdata", "id": "1"}),
function(data) {
alert("Done");
}
);
And the relevant section of the Apache configuration file is
RewriteEngine on
RewriteRule ^/backend http://localhost:8080 [proxy]
CherryPy is running with no special startup options:
cherrypy.config.update({'server.socket_port': 8080})
cherrypy.quickstart(MyServer())

Have you considered using mod_proxy and ProxyPass? It's sort of more suited to what it looks like you're trying to do. You'd simply need a directive like this:
ProxyPass /backend http://localhost:8080/
You can add connection timeouts, retry attempts, rewrite cookie domains, even rewrite response header hostnames with ProxyPassReverse.

This actually turned out to just be a case of failing to manually include a header in the AJAX request that specified the Content-Type as application/json. For example,
$.ajax({
...,
headers: {"Content-Type": "applicaton/json"},
...
});

Related

Mixed content jQuery ajax HTTPS request has been blocked on Laravel

I think this question will be easy for someone and will be a face-palm situation for me.
I have a Laravel 5.3 site, and various pages have ajax requests. Because I use the csrf_field() feature, they work fine.
But there is one page where the ajax produces this error:
Mixed Content: The page at 'https://example.com/fb/reports' was loaded over HTTPS, but requested an insecure XMLHttpRequest endpoint 'http://example.com/fb/json?levelType=&id=&aggLevel=ad&start=&end='. This request has been blocked; the content must be served over HTTPS.
My javascript looks like this:
var relUrl = '/fb/json/';
var payload = {
levelType: levelType,
id: id,
aggLevel: aggLevel,
start: start,
end: end
};
console.log(relUrl);
return $.ajax({
type: 'GET',
dataType: 'json',
data: payload,
url: relUrl,
headers: {
'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content')
}
});
I've read tons of articles about this error. I've tried tons of suggested solutions, including changing the relative URL to the full https URL, or starting it with 2 slashes.
I've even tried changing the way my Laravel routes work and am now using just querystring parameters.
I've studied all of the articles below (and more).
Also, since this one ajax query is in a password-protect part of the site (and the ajax queries that work are in a public/open part of the site), I figured maybe that was related to the problem. But then I used SSH to log into the production server and vim to temporarily remove the line that required any authentication, and the https error still happens.
What steps can I take to debug further from here? What logs can I 'tail' on my Cloudways server?
Is there anything that Cloudflare might be interfering with (which I doubt, since other ajax queries work, all on https)?
Thanks!
jQuery AJAX Request to HTTPS getting served to HTTP with Laravel and Select2
This request has been blocked; the content must be served over HTTPS
Mixed content issue - insecure XMLHttpRequest endpoint
XHR response blocked by Chrome, because of mixed content issue (http/https)
Forcing AJAX call to be HTTPS from HTTPS Page
MixedContent when I'm loading https page through ajax, but browser still thinks it's http
jQuery ajax won't make HTTPS requests
Laravel 5.1 ajax url parameter is url
Summary:
I needed to replace var relUrl = '/fb/json/'; with var relUrl = '/fb/json'; (remove the trailing slash) because that's what my Laravel web.php routes file expected.
In Chrome console, I noticed that the https XHR request was being "canceled" and replaced with an http request.
So then I used ssh to log into the remote production server and vim to temporarily disable the requirement of authentication.
Then in the Chrome console, I defined and ran a new ajax command using an absolute https URL with querystring params on the end. That worked (no mixed content error). Then I tried a relative URL like that, and it worked too.
Even a relative URL with no payload or querystring params or trailing slash worked.
Then I added the trailing slash again, and it didn't work.
I still wish there had been an easier way to trace or debug the redirect paths or whatever was happening. I still feel like I stumbled onto the answer clumsily (after many hours) instead of knowing how to dissect this problem reliably.
When changing from HTTP to HTTPS, it's possible to get the problem Mixed content issue - Content must be served as HTTPS.
So, first, modify APP_URL in the .env file, if we use the assets helper, this shouldn't give any problem with the URL.
APP_URL=https://url.net
Finally, add the following to the beginning of **api.php** or **web.php**:
if (App::environment('production')) {
URL::forceScheme('https');
}

React JS + React Router works with $.get but not $.ajax PUT

I've got a react.js setup and I've got some simple routes using react-router. I have a dispatcher:
import dispatcher from "../dispatcher";
export function reloadList(){
dispatcher.dispatch({type: "FETCH_LIST"});
let serverRequest = $.get("../../data/list.json",
function(data){
console.log(data); //Logs correct data from list.json
}
);
}
export function saveList(list){
dispatcher.dispatch({type: "SAVE_LIST"});
let serverRequest =
$.ajax(
url: "../../data/list.json",
dataType: 'json',
method: 'PUT',
data: list,
success: function(data) {
console.log("success!"); //does not output
},
error: function(xhr, status, err) {
console.log(status, err.toString()); //outputs a 404 error
}
});
)
}
The reloadList() function runs fine and outputs the JSON data. The saveList() function throws a 404 error. I'm assuming this is because of the way the app handles routes, but I'm confused as to why it works with get and not put (or post for that matter).
I've been struggling with saving data to a file in react, this seemed like the right way at first but now I'm not so sure. Is there something I'm doing wrong here?
I'm going to assume based on your phrasing, that you're using some sort of simple HTTP server (or no server at all) for developing locally, and list.json is a file on your machine. If this is the case, your issue is that your HTTP server doesn't have the routing to know how to handle PUTs (or POSTs, or probably any method other than GET for that matter). If you want to write files to your system you will need to add an actual backend that can handle a PUT and more intelligently interact with the filesystem.
Unfortunately there's no simple way to write files to disk in the browser alone (for security reasons), but if you want to avoid adding to your backend, you could look into creating files for download using a Blob
You can't change the contents of a file on the server from the browser using only an ajax request. Think about how terribly insecure the internet would be if I could change files on your server just by sending an ajax request.
You're going to need some server side code that can handle such a request. For instance, you can setups a simple Node / Express server that has a route which can handle reading and writing to disk, using the built in fs module.
Maybe later on you'll want to use a database instead.
http://expressjs.com/en/starter/installing.html
Make sure your server routes the PUT request, not just GET.
For example express.js routes like this:
`app.get("/getRequestHere",function(){});
app.put("/putRequestHere",function(){});`
Some browsers (Chrome) restrict the ability to make PUT/DELETE requests. It sents out an OPTION request that returns 404. What you want to do is put this in your .htaccess file:
Header always set Access-Control-Allow-Origin "*"
Header always set Access-Control-Allow-Methods "POST, GET, OPTIONS, DELETE, PUT"
Header always set Access-Control-Max-Age "1000"
Header always set Access-Control-Allow-Headers "x-requested-with, Content-Type, origin, authorization, accept, client-security-token, accessToken"
# Added a rewrite to respond with a 200 SUCCESS on every OPTIONS request.
RewriteEngine On
RewriteCond %{REQUEST_METHOD} OPTIONS
RewriteRule ^(.*)$ $1 [R=200,L]
first parts accepts access for PUT methods,
second part forwards (rewrite) OPTION method requests into an 200 response. This code I copied somewhere else on stackoverflow and it totally works.
(stop down voting me guys. This answer totally works)

REST request from app works, but not from javascript

I'm building an app that has to get and set data at a remote web service through requests. When I use the jQuery GET request it works fine, I can request data from the service without any problems, but when I use PUT I get some erros:
OPTIONS http://myurl.com 501 (Unsupported method
('OPTIONS'))
OPTIONS http://myurl.com Origin null is not allowed by Access-Control-Allow-Origin.
I've tried almost anything to get this to work, but it won't work. I've download a chrome app called REST Console, which can make custom REST requests. The strange thing is that I can interact with my server over that app but not through my javascript!
This is the javascript:
$.ajax({
url: 'http://myurl.com',
type: 'PUT',
data: '<time>16:00</time>',
success: function(data) { alert(data); }
});
Could anybody tell me what is going on here?
First ensure you're serving the page that runs the script from a web server, not directly from the file system.
I'm guessing your service at http://myurl.com is at a different host name to the host name your page is being served from? For it to work in this case you need to implement HTTP headers to support Cross Origin Resource Sharing.
Your service at http://myurl.com needs to handle an HTTP OPTIONS request, the response to which should be a set of HTTP headers (with no content) as follows:
Access-Control-Allow-Origin: http://url-of-page-with-javascript/
Optionally you can also specify Access-Control-Allow-Credentials, Access-Control-Allow-Headers and Access-Control-Allow-Methods. See the full specification here.
You'll also need to add the same headers with the same values when your server responds to the PUT request - obviously the content will also be included with this response.

AJAX URL requests in Drupal 7 on localhost Apache2 don't include base URL or base path

I am currently stuck with a problem in my local Drupal 7 environment. As Drupal 7 site configurations can get very complex, I will try to explain my problem in as much details as possible.
The site sits in a sub folder in my local environment, I have more projects running on my localhost, so preferably I would like to keep the projects separated. In addition, for this site I have two separate folders, one for development and one for production that share the same database, so a solution by adding fake domains would not work here I think (correct me if I'm wrong).
So the main problem seems to be that AJAX requests don't include the base URL or base path and I can't login on http://localhost/mysite/devel/docroot/user because the AJAX request would go to http://localhost/system/ajax or http://localhost/ajax_register/login/ajax and therefore would not return the correct JSON response.
How can this be solved? Are configurations in Apache's httpd.conf or .htaccess enough to make this work?
Here's what I did so far, first in settings.php:
$base_url = 'http://localhost/mysite/devel/docroot';
$base_path = '/mysite/devel/docroot/';
Next, I've tried the following with rewrite rules in httpd.conf:
<IfModule mod_rewrite.c>
RewriteEngine on
RewriteCond %{HTTP_REFERER} .*devel.*$ [OR]
RewriteRule ^/sites/(.*)$ /mysite/devel/docroot/sites/$1
RewriteRule ^/system/(.*)$ /mysite/devel/docroot/system/$1
RewriteRule ^/ajax_register/(.*)$ /mysite/devel/docroot/ajax_register/$1
</IfModule>
Here I got the following pop up with HTML (that seems to be from index.php) in the response text instead of the expected JSON response:
An AJAX HTTP error occurred.
HTTP Result Code: 404
Debugging information follows.
Path: http://localhost/ajax_register/login/ajax
StatusText: error
ResponseText: lots of HTML...
Then without rewrite rules but using proxies instead in httpd.conf:
<IfModule mod_proxy.c>
ProxyRequests Off
ProxyPreserveHost On
<Proxy *>
Order deny,allow
Allow from all
</Proxy>
RewriteEngine on
ProxyPass /system/ http://localhost/mysite/devel/docroot/system/
ProxyPassReverse /system/ http://localhost/mysite/devel/docroot/system/
<Location /system/>
Order allow,deny
Allow from all
</Location>
ProxyPass /ajax_register/ http://localhost/mysite/devel/docroot/ajax_register/
ProxyPassReverse /ajax_register/ http://localhost/mysite/devel/docroot/ajax_register/
<Location /ajax_register/>
Order allow,deny
Allow from all
</Location>
</IfModule>
For the proxy directives, a similar 404 not found error was given for the POST AJAX request, except that now the response text is in JSON format.
An AJAX HTTP error occurred.
HTTP Result Code: 404
Debugging information follows.
Path: http://localhost/ajax_register/login/ajax
StatusText: error
ResponseText: some JSON code...
Without both the rewrite rules and the proxy directives I get the following error in the JavaScript pop up:
An AJAX HTTP error occurred.
HTTP Result Code: 404
Debugging information follows.
Path: http://localhost/ajax_register/login/ajax
StatusText: error
ResponseText:
404 Not Found
Not Found
The requested URL /ajax_register/login/ajax was not found on this server.
Finally in .htaccess I've tried to rewrite the base to the following:
RewriteBase /mysite/devel/docroot/
and here I get the same 404 error as was the case when both the rewrite rules and proxy directives are commented out in httpd.conf. I would also like to add that in the database, in the table languages I've set the domain for the English language to localhost.
I don't understand, why is the base not included in front of the AJAX URL requests? And how can I add it? When I query Drupal.settings.basePath in Firebug I do get the value that I've set in settings.php :S - Does someone have any ideas?
There are many solutions for your problem, but I'm gonna try to focus on the most mature one. I assume you are using windows as your environment.
You said you were running your projects on localhost, which is where your first mistake is.
Localhost is nothing but a form of weird domain name you specify. When you request a domain like "www.google.com" or "localhost" the following steps occur:
The browser checks a specific file for the requested domain. This file is called hosts file
If the domain name is found in the hosts file, the browser sends a request to the IP address specified in the hosts file
If the domain name is not found in the hosts file, the browser queries domain name servers which return the corresponding IP adress.
Now localhost is nothing but a domain name specified in your hosts file, which points to the loopback address.(127.0.0.1).
So the magic trick here is to bind your custom hosts like "project1", "project2" etc.. to that loopback adress(127.0.0.1).
Than when you send a request to "project1" in your browser, the server running on port 80 will respond as if you typed "localhost".
The second part you need to take care of is called virtual hosts. When you send a request with a specific domain name, a special header is included in your http request called "Host".
Lets assume, that you redirect all this custom domains to the same IP (127.0.0.1). In order for apache to serve a different project, you should instruct apache to look at the "Host" header and resolve it for the corresponding project.
Again you do that by setting virtual hosts.
A lot of frameworks and content managing systems in PHP have some ugly ways to insert some magic "$BASE_PATH" variable, which is a bad practice as that could be achieved with relative paths in pure html and a properly configured server.

Ajax request works in remote server but not in local server (with Codeigniter)

I've a web application wich makes Ajax requests to a server with Codeigniter-php code. The Ajax requests work correctly in local server but not when the application is hosted in remote server.
The console errors are:
XMLHttpRequest cannot load http://localhost/CI-example/index.php/control/controlHome. Origin http://www.page.com is not allowed by Access-Control-Allow-Origin.
Surprisingly, the request is made in the server but not the response.
The URL that I use to Ajax request is:
AJAX_URL = "http://localhost/CI-example/site/index.php/control/controlHome";
But, also I've tried with:
AJAX_URL = "http://www.page.com/CI-example/site/index.php/control/controlHome";
And the next error is captured:
POST http://www.page.com/webdom/site/index.php/control/controlHome 500 (Internal Server Error)
How can I do?
Edit:
www.page.com is a subdomain. Is necessary to do some configuration when a subdomain is used to Ajax request?
And the folders organization is:
/CI-example
---/application/controllers/control.php
---/system
---/site/js/ajaxRequest.js
As I am getting here, while you are sending ajax requests to the server than it's returning 500 (Internal Server Error). I'm sure that the error is from server side, and there may be following reason-
If everything is fine in the codes, then may be your base_url is different from what you are requesting. Yes this can cause the problem, for example if you have hosted your web application and your base_url is www.mysite.com and you are requesting for mysite.com.
Next reason may be, that you have developed your project in windows or any system which is in-case-sensitive but when you will upload to any linux like server than each and every file name will be case-sensitive. For example suppose a model file name you have given is MyModel.php but when you will load the model, it will generate the error like Unable to find the specific class.
You cannot make HTTP POST requests using AJAX to a different domain, unless that page allows you to do so using a special header called "Access-Control-Allow-Origin".
localhost is different to page.com which is why this will not work.
Response on the http://www.page.com's url say something has gone wrong during the page execution. Your PHP error log should help you to find what.
Adding the line ini_set('display_errors', 1) might return the error to the ajax request, in the error handler. Don't forget to remove the line after use, you don't want this lying around in production code.
The second error is : 500 (Internal Server Error)
This means there was an error on the server side - not a cross-origin policy problem.
This is probably an error in the execution of your PHP script.
Check your error log (e.g : if you use the standard LAMP stack, the error log should be somewhere in /var/log/apache2/)
try this,
http://localhost/CI-example/index.php/control/controlHome
instead of
http://localhost/CI-example/site/index.php/control/controlHome
in your ajax URL.
As from your folder structure, there is no need to include "site" in your URL

Categories

Resources