Missing CORS headers in response from PHP/Apache2 - php

A Zend Expressive project my company is working on is ready to be shipped but in our staging environment we seem to be missing response headers for a CORS pre-flight request. This does not happen in our development environment. We're using CorsMiddleware in our pipeline but it doesn't look like that middleware is the culprit.
The problem
During runtime, the middleware detects incoming pre-flight requests and it will reply with a response like so:
HTTP/1.1 200 OK
Date: Mon, 20 Aug 2018 15:09:03 GMT
Server: Apache
X-Powered-By: PHP/7.1.19
Access-Control-Allow-Origin: https://example.com
Vary: Origin
Access-Control-Allow-Headers: content-type
Keep-Alive: timeout=5, max=100
Connection: Keep-Alive
Transfer-Encoding: chunked
Content-Type: text/html; charset=UTF-8
Well, that only works on our development servers and php's built-in webservers. The response is different from our staging server, even though the request is exactly the same, apart from the host:
HTTP/1.1 200 OK
Date: Mon, 20 Aug 2018 15:11:29 GMT
Server: Apache
Keep-Alive: timeout=5, max=100
Cache-Control: max-age=0, no-cache
Content-Length: 0
Content-Type: text/html; charset=UTF-8
What we've tried
Investigating the middleware
We've verified that CorsMiddleware runs perfectly fine and actually sets the required headers. When we modify CorsMiddleware's response code and set it to 202 instead of 200 we now do get the headers we're looking for. Changing the response code back to 200 makes the headers disappear again.
Setting the headers manually
Using the following example:
header('Access-Control-Allow-Origin: https://example.com');
header('Access-Control-Allow-Headers: content-type');
header('Vary: Origin');
exit(0);
This has the same behavior until we modify the response code to 204 or anything other than 200.
Looking at the body
The response body is empty and shouldn't contain anything but when we add content to the response body the headers appear as if nothing was wrong.
So if I add body content, the headers are present. No body content? No CORS headers. Is this some setting in Apache? Am I missing some configuration in PHP? Am I forgetting anything?
Further details
All requests have been tested with httpie, Postman, curl and PhpStorm's http client.
Here's the httpie example:
http -v OPTIONS https://staging.****.com \
'access-control-request-method:POST' \
'origin:https://example.com' \
'access-control-request-headers:content-type'
Here's the curl example:
curl "https://staging.****.com" \
--request OPTIONS \
--include \
--header "access-control-request-method: POST" \
--header "origin: https://example.com" \
--header "access-control-request-headers: content-type"
Cors configuration in pipeline.php (wildcard only for testing):
$app->pipe(new CorsMiddleware([
"origin" => [
"*",
],
"headers.allow" => ['Content-Type'],
"headers.expose" => [],
"credentials" => false,
"cache" => 0,
// Get list of allowed methods from matched route or provide empty array.
'methods' => function (ServerRequestInterface $request) {
$result = $request->getAttribute(RouteResult::class);
/** #var \Zend\Expressive\Router\Route $route */
$route = $result->getMatchedRoute();
return $route ? $route->getAllowedMethods() : [];
},
// Respond with a json response containing the error message when the CORS check fails.
'error' => function (
ServerRequest $request,
Response $response,
$arguments
) {
$data['status'] = 'error';
$data['message'] = $arguments['message'];
return $response->withHeader('Content-Type', 'application/json')
->getBody()->write(json_encode($data));
},
]);
The staging environment:
OS: Debian 9.5 server
Webserver: Apache/2.4.25 (Debian) (built: 2018-06-02T08:01:13)
PHP: PHP 7.1.20-1+0~20180725103315.2+stretch~1.gbpd5b650 (cli) (built: Jul 25 2018 10:33:20) ( NTS )
Apache2 vhost on staging:
<IfModule mod_ssl.c>
<VirtualHost ****:443>
ServerName staging.****.com
DocumentRoot /var/www/com.****.staging/public
ErrorLog /var/log/apache2/com.****.staging.error.log
CustomLog /var/log/apache2/com.****.staging.access.log combined
<Directory /var/www/com.****.staging>
Options +SymLinksIfOwnerMatch
AllowOverride All
Order allow,deny
allow from all
</Directory>
SSLCertificateFile /etc/letsencrypt/live/staging.****.com/fullchain.pem
SSLCertificateKeyFile /etc/letsencrypt/live/staging.****.com/privkey.pem
Include /etc/letsencrypt/options-ssl-apache.conf
</VirtualHost>
</IfModule>
Apache2 vhost on development:
<VirtualHost *:443>
ServerName php71.****.com
ServerAdmin dev#****.com
DocumentRoot /var/www/
<Directory /var/www/>
Options Indexes FollowSymlinks
AllowOverride All
Require all granted
</Directory>
ErrorLog ${APACHE_LOG_DIR}/error.ssl.log
CustomLog ${APACHE_LOG_DIR}/access.ssl.log combined
SSLEngine On
SSLCertificateFile /etc/ssl/certs/****.crt
SSLCertificateKeyFile /etc/ssl/certs/****.key
</VirtualHost>
To everybody pointing fingers to Cloudflare:
Try this direct link with httpie. This link is not using cloudflare:
http -v OPTIONS http://37.97.135.33/cors.php \
'access-control-request-method:POST' \
'origin:https://example.com' \
'access-control-request-headers:content-type'
Check the source code in your browser: http://37.97.135.33/cors.php?source=1

From everything I read here, including your comments it seems your "production" server is behind a PROXY more exactly CloudFlare. You have given details about your working development envinroment, but nothing about the non-working production environment.
Your setup seems correct, and if it does work on a development setup without a PROXY, it means that the PROXY is modifying the headers.
A quick search about this regarding CloudFlare has given enough indication that CloudFlare can be the cause of your problem.
I strongly suggest you enable "Development Mode" in CloudFlare so it will bypass the cache and you can see everything coming/going to the origin server.
The following article should help you understand and resolve your issue:
https://support.cloudflare.com/hc/en-us/articles/203063414-Why-can-t-I-see-my-CORS-headers-
UPDATE:
It appears that your issue is from Apache Mod Pagespeed, by turning it off your headers are present all times.
It is still unclear why the mod is stripping your headers, but that's for another question and time.

Your configuration makes it clear that the headers do get generated, so it's not the code or the middleware's fault.
I believe that the headers get removed by something - check Apache's mod_headers and configuration in case there's a rogue unset directive.
Another, less likely possibility is that you're looking at the staging server through a load balancer or proxy of some kind, which rewrites the headers and leaves the CORS out (to verify that, you might need to intercept Apache's outgoing traffic).
I have made both mistakes, myself.

Please make sure you have the right configuration in Zend Expressive. For example the code below will allow CORS access to any calling domain
use Psr\Http\Message\ServerRequestInterface;
use Tuupola\Middleware\CorsMiddleware;
use Zend\Expressive\Router\RouteResult;
$app->pipe(new CorsMiddleware([
"origin" => ["*"],
"methods" => ["GET", "POST", "PUT", "PATCH", "DELETE"]
}
]));

Related

Bad Gateway: The proxy server received an invalid response from an upstream server

I have a built-in PHP development server running on a random port and I am trying to configure secure API requests with Apache Reverse Proxy.
Apache2 listens on port 443 and passes requests to the server, the server processes the request and passes the JSON response back to Apache2 but for some reason, there is an error.
Everything works well when I try to access the upstream server directly. There is no typo.
SSL and ReverseProxy work.
Servers are running on Ubuntu.
Mime mod is enabled and I have added json to the file formats Apache2 should serve in /etc/apache2/sites-enabled/000-default.conf.
The PHP is most likely the culprit but how do I make it better? I've been trying to figure this out for a month now.
Or is there a better way to secure API requests to the PHP server? I tried to achieve this using tunnel but was not successful due to the constant occurrence of errors.
The PHP code on the upstream server.
header ("Access-Control-Allow-Origin");
header ("Content-Type: application/json; charset=utf8");
header ("Access-Control-Allow-Methods: OPTIONS,GET,POST,PUT,DELETE");
header ("Access-control-Max-Age: 3600");
header ("Access-Control-Allow-header: Content-Type, Access-Control-Allow-Headers, Authorization, X-Requested-With");
header ("HTTP/1.1 200 OK");
echo json_encode (array ("BODY"=>"hello world", "status_code_header"=>"HTTP/1.1 200 Ok"));
apache2.conf
<VirtualHost *:443>
ServerName ...
ErrorLog ...
CustomLog ...
SSLEngine On
SSLCertificateFile ...
SSLCertificateKeyFile ...
ProxyPass / http://localhost:port/ retry=1 acquire=3000 timout=600 Keepalive=On
ProxyPassReverse / http://localhost:port/
</VirtualHost>
Apache2 error.log
bad HTTP/1.1 header returned by /person/

React, API Platform - No 'Access-Control-Allow-Origin' header is present on the requested resource

I hosted my website on a VPS with only one domain name.
I've an API build with API Platform and a front build with React.
I set up 2 vhosts one for my API and one for my front like that :
API :
<VirtualHost *:80>
ServerName my-api.project.fr
ServerAlias www.my-api.project.fr
DocumentRoot path/to/my/api-project/public
DirectoryIndex /index.php
<Directory path/to/my/api-project/public>
AllowOverride None
Order Allow,Deny
Allow from All
FallbackResource /index.php
</Directory>
</VirtualHost>
FRONT :
<VirtualHost *:80>
ServerName my-front.project.fr
ServerAlias www.my-front.project.fr
DocumentRoot path/to/my/front-project/build
DirectoryIndex index.html
<Directory "path/to/my/front-project/build">
Options +FollowSymLinks
AllowOverride all
Require all granted
FallbackResource /index.html
</Directory>
</VirtualHost>
Before each request I authenticate my front via an API call which returns a token which I put in the local storage. The url is: http://my-api.fr/api/guest/client/generate-public-token
I have no problem with this call, it works perfectly.
However, I've a registration endpoint (http://my-api.fr/api/guest/account/register) which doesn't work and the browser returns : Access to XMLHttpRequest at 'http://my-api.project.fr/api/guest/account/register' from origin 'http://my-front.project.fr' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource. I really don't understand why this call doesn't work but not the other one...
In my API, I've Nelmio Bundle and my config is :
nelmio_cors:
defaults:
origin_regex: true
allow_origin: ['%env(CORS_ALLOW_ORIGIN)%']
allow_methods: ['GET', 'OPTIONS', 'POST', 'PUT', 'PATCH', 'DELETE']
allow_headers: ['Content-Type', 'Authorization', 'Origin']
expose_headers: ['Link']
max_age: 3600
paths:
'^/': ~
Variable CORS_ALLOW_ORIGIN is equal to ^https?://my-front.project.fr(:[0-9]+)?$ but it still doesn't work.
I don't know if it can help someone but headers of my request are :
POST /api/guest/account/register HTTP/1.1
Host: my-api.project.fr
Connection: keep-alive
Content-Length: 120
Accept: application/json, text/plain, */*
Authorization: Bearer my_token
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.130 Safari/537.36
Content-Type: application/json;charset=UTF-8
Origin: http://my-front.project.fr
Referer: http://my-front.project.fr/register
Accept-Encoding: gzip, deflate
Accept-Language: fr-FR,fr;q=0.9,en-US;q=0.8,en;q=0.7
Thanks in advance.
Bad config on my API Vhost...
I've to change AllowOverride None by AllowOverride All beacuse I've an .htaccess file
sounds like you need cors https://enable-cors.org/server_php.html. If you don't have access to configure Apache, you can still send the header from a PHP script. It's a case of adding the following to your PHP scripts:
<?php
header("Access-Control-Allow-Origin: *");

.htaccess headers being ignored by Apache

I have a website that uses the same core .htaccess details as many other websites; however this website does not properly load the .htaccess directives -- giving a basic HTTP header set of:
HTTP/1.1 200 OK
Date: Mon, 12 Nov 2018 09:34:28 GMT
Server: Apache
Keep-Alive: timeout=5, max=100
Connection: Keep-Alive
Transfer-Encoding: chunked
Content-Type: text/html; charset=UTF-8
The website itself loads fine, but additonal headers in .htaccess are not being agknowledged / loaded.
So .htaccess is being read, right?
Yes -- The htaccess file contains HTTPS forced redirects and domain name redirects (from the .co.uk to .com address (both to the same website account))
These work.
Headers supplied by PHP are being loaded fine, too
The PHP headers on a test page are loading just fine:
<?php
header("Cache-Control: no-cache, must-revalidate");
header('Content-Type: text/html; charset=utf-8');
header("X-Clacks-Overhead: GNU Terry Pratchett");
header("Content-Language: en");
header("X-XSS-Protection: 1; mode=block");
header("X-Frame-Options: SAMEORIGIN");
header("X-Content-Type-Options: nosniff");
?>
But the same headers set in the .htaccess are not being agknowledged.
So it's an .htaccess syntax error!
Not that I can see; usually with a .htaccess error the site loads an HTTP-500 error message, however here the site loads in the browser without issue.
When there IS a deliberate syntax error the error-500 HTTP response comes back as expected.
Ok bozo, check your error logs!
Absolutely; I couldn't agree more. The Apache error logs are empty!
What have you tried to do to fix this?
Confirmed httpd.conf allows reading of .htaccess
Confirmed that mod_headers.c is loaded on the server
Commented out and re-written various rules, to no effect
Read lots (maybe 6-8) of posts on Stack Overflow and Server Fault - Stackoverflow posts don't appear to relate or their issues had distinct differences.
Confirmed my .htaccess has the correct permissins (0644)
Told my staff (He's a Graphic Designer).
Cried myself to sleep.
Right then - Get your file out! Show me the magic!
Here:
Options +FollowSymLinks
Options -Indexes
RewriteEngine On
ErrorDocument 404 /index.php?msg=404
ErrorDocument 403 /index.php?msg=403
#Set asset items to cache for 1 week.
<FilesMatch "\.(gif|jpe?g|png|ico|css|js|swf|mp3)$">
Header set Cache-Control "max-age=1972800, public, must-revalidate"
</FilesMatch>
RewriteCond %{HTTPS} !=on
RewriteRule ^ https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301]
## This does not appear to work (for either)
#Header always set Strict-Transport-Security "max-age=31536000;" env=HTTPS
Header always set Strict-Transport-Security "max-age=31536000; includeSubdomains;" "expr=%{HTTPS} == 'on'"
Header set Expect-CT enforce,max-age=2592000
RewriteCond %{HTTP_HOST} ^(www\.)?thewebsite\.co\.uk$ [NC]
RewriteRule ^/?(.*)$ https://www.thewebsite.com%{REQUEST_URI} [R=301,L]
###
##### Seems to workdown to roughly this point.
###
#force requests to begin with a slash.
RewriteCond %{REQUEST_URI} !^$
RewriteCond %{REQUEST_URI} !^/
RewriteRule .* - [R=403,L]
RewriteCond %{HTTP_HOST} !^$
RewriteCond %{HTTP_HOST} !^www\. [NC]
RewriteRule ^ https://www.%{HTTP_HOST}%{REQUEST_URI} [R=301,L]
RewriteCond %{ENV:REDIRECT_STATUS} 200
RewriteRule .* - [L]
### This file does not exist on the directory at present.
<Files .account-user.ini>
order allow,deny
deny from all
</Files>
###
#### None of these appear on assessment tools such as Security Headers
#### Or redbot.
###
Header set Cache-Control no-cache,must-revalidate
Header set X-Clacks-Overhead "GNU Terry Pratchett"
Header set X-XSS-Protection 1;mode=block
Header set X-Content-Type-Options nosniff
Header always set X-Frame-Options SAMEORIGIN
Header set Expect-CT enforce,max-age=2592000
Header set Content-Language en
Header set Referrer-Policy origin-when-cross-origin
<LimitExcept GET POST HEAD>
deny from all
</LimitExcept>
And finally it would really help if you gave me a final summary of all of the above!
Header setting commands in .htaccess do not appear to work.
ALL parts of the file are used on other live sites elsewhere without issue.
Headers can be set in PHP without issue
No errors arise from these Headers in the .htaccess.
Headers appear to fail silently.
No Apache error logs are recorded.
The .htaccess is being read by Apache because other commands (such as mod_Rewrites) are being actioned
UPDATE:
From research by other parties (the hosting providers) it seems that somehow the .htaccess works and loads all the correct headers for non PHP pages.
For even plain PHP pages; the headers are blank.
Clarification
whatever.html pages load the headers all ok.
PHP pages display headers set by Header("...");
PHP pages refuse to load any headers set by .htaccess. This is the problem.
So it looks like my .htaccess can't set headers for PHP pages. How can I fix this?
It seems that PHP ignores headers defined in .htaccess when working as a FastCGI module.
There are a lot of suggestions how to fix this. In your case I would recommend to have a file that defines all your headers
<?php
// file headers.php
header('Cache-Control: no-cache,must-revalidate');
header('X-Clacks-Overhead: "GNU Terry Pratchett"');
header('X-XSS-Protection: 1;mode=block');
header('X-Content-Type-Options: nosniff');
header('X-Frame-Options: SAMEORIGIN');
header('Expect-CT: enforce,max-age=2592000');
header('Content-Language: en');
header('Referrer-Policy: origin-when-cross-origin');
?>
and save it to your DocumentRoot directory. Then add this entry to your .htaccess file to include it with every request:
php_value auto_prepend_file /var/www/html/headers.php
Testing it:
<?php
// file test.php
die("hello world");
?>
And the headers are being sent:
$ curl -I ubuntu-server.lan/test.php
HTTP/1.1 200 OK
Date: Sun, 25 Nov 2018 09:37:52 GMT
Server: Apache/2.4.18 (Ubuntu)
Cache-Control: no-cache,must-revalidate
X-Clacks-Overhead: "GNU Terry Pratchett"
X-XSS-Protection: 1;mode=block
X-Content-Type-Options: nosniff
X-Frame-Options: SAMEORIGIN
Expect-CT: enforce,max-age=2592000
Content-Language: en
Referrer-Policy: origin-when-cross-origin
Content-Type: text/html; charset=UTF-8
Always keep in mind that when you change headers in .htaccess to also change them in headers.php.
Hope this helps!
➥ previous answer
I think this problem results from the httpd/apache2 headers_module not being loaded correctly (although you state otherwise in one of the above comments). You can check this by executing this command in the terminal:
apachectl -M | grep headers_module
If you get no output headers_module (shared) (or similar), then you have to activate the httpd/apache2 headers module. On a CentOS system you have to load the respective source file in your configuration (default /etc/httpd/conf/httpd.conf).
You have to add this line
LoadModule headers_module /usr/lib/apache2/modules/mod_headers.so
and then restart the http server wih sudo systemctl restart httpd.service
With EasyApache 4 the folder where httpd/apache2 modules are located might differ and be /usr/lib64/apache2/modules/.
I hope this helps!
It is not so much FastCGI as it is mod_proxy_fcgi, the method of asking Apache to "execute" FastCGI by passing it to some other listener.
When you use any mod_proxy* module, .htaccess isn't processed at all, because you're acting as a proxy and short-circuiting any disk-related configuration sections.
php-fpm will be looking at the request URL and reading data from disk, but Apache isn't. It is just confusing to people because they can be running on the same host and the files are often in a directory httpd could serve directly.
After much exploration it was found the issue was the PHP Handler -- the fastCGI (cgi) handler was not keeping the headers.
Changing to the suphp handler immediately resolved the issues.
I had same problem.
Please enable cache module in Linux Ubuntu.
sudo a2enmod cache
Then run:
sudo service apache2 start

ip works, domain doesn't, curl -v finds ip but returns empty reply

My site works with ip but not with domain.
When I curl -v 'example.com' (with my domain in place of example) I get:
* Rebuilt URL to: example.com/
* Trying 123.123.123.123...
* Connected to example.com (123.123.123.123) port 80 (#0)
> GET / HTTP/1.1
> Host: example.com
> User-Agent: curl/7.47.0
> Accept: */*
>
* Empty reply from server
* Connection #0 to host example.com left intact
curl: (52) Empty reply from server
However, when I curl -v '123.123.123.123' (with my ip in place of 123.123.123.123) all works fine and I get:
* Rebuilt URL to: 123.123.123.123/
* Trying 123.123.123.123...
* Connected to 123.123.123.123 (123.123.123.123) port 80 (#0)
> GET / HTTP/1.1
> Host: 123.123.123.123
> User-Agent: curl/7.47.0
> Accept: */*
>
< HTTP/1.1 200 OK
< Server: nginx
< Date: Sun, 17 Sep 2017 06:45:56 GMT
< Content-Type: text/html; charset=UTF-8
< Transfer-Encoding: chunked
< Connection: keep-alive
< Vary: Accept-Encoding
<
<!DOCTYPE html>
<html lang="en">
<head>
<title>Hello World Test Page</title>
</head>
<body>
<h1>Hello World</h1>
<p>Test page.</p>
</body>
</html>
* Connection #0 to host 123.123.123.123 left intact
I get the same behavior in browsers. Hello world page shows with ip but not with domain.
What could I possibly be missing?
The hello world content returned when curling the ip is exactly the content of my index.php file as expected.
I set the DNS more than 48 hours ago so that shouldn't be the problem (and doesn't seem to be seeing curl returns the correct ip when queried on the domain).
I have tried adding a default .htaccess file with the content below but this didn't change the result.
# basic compression
<IfModule mod_gzip.c>
mod_gzip_on Yes
mod_gzip_dechunk Yes
mod_gzip_item_include file \.(html?|txt|css|js)$
mod_gzip_item_include mime ^text/.*
mod_gzip_item_include mime ^application/x-javascript.*
mod_gzip_item_exclude mime ^image/.*
mod_gzip_item_exclude rspheader ^Content-Encoding:.*gzip.*
</IfModule>
# Protect files and directories
<FilesMatch "(\.(engine|inc|info|install|module|profile|po|sh|.*sql|theme|tpl(\.php)? |xtmpl)|code-style\.pl|Entries.*|Repository|Root|Tag|Template)$">
Order allow,deny
</FilesMatch>
# Don’t show directory listings
Options -Indexes
# Basic rewrite rules, stop unneeded PERL bot, block subversion directories
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteRule ^(.*/)?\.svn/ - [F,L]
ErrorDocument 403 "Access Forbidden"
RewriteCond %{HTTP_USER_AGENT} libwww-perl.*
RewriteRule .* – [F,L]
</IfModule>
I have scraped stackoverflow for tonnes of similar questions but none that I've found seem to be the exact same issue.
Any ideas? Thanks in advance.
(PS: I'm really not sure about the tags that I've added coz I really don't know where the problem is).
You have to let curl follow any redirect by using -L
So
curl -v -L 'example.com'
First thing try to check that the domain is properly configured and resolving to the IP of your instance/server:
dig example.com +short
That should give you the IP of your server in case you are not using a CDN something like CloudFlare
If that is working check that you have the web server properly configured to receive requests from your domain, in case you were using Nginx you could have something like this:
server {
listen 80;
server_name *.example.com;
...
}
Notice the server_name *.example.com

Apache 2.4: PHP files are not being sent to the browser

I'm setting up a new site locally on a Windows machine for testing. In the document root, if I have an index.html it is served to the browser without problem. If I rename it index.php, the browser receives nothing. No error is raised server-side. I'm trying to understand why.
Vhosts
<VirtualHost *:80>
DocumentRoot "C:\websites\learn"
ServerName learn.loc
LogLevel alert rewrite:trace2
#PHP SETTINGS
php_value auto_prepend_file "C:\websites\learn\noop.php"
php_value open_basedir "C:\websites\learn"
<Directory "C:\websites\learn">
Options Indexes FollowSymLinks
AllowOverride All
Require all granted
</Directory>
</VirtualHost>
Here is the .htaccess file that resides in the document root:
RewriteEngine on
#point to javascript learning project
RewriteRule ^js /javascript
RewriteRule ^js/(.*) /javascript/$1
Here is the mod_rewrite log generated when I load learn.loc/javascript (this folder has an index.php file)
[initial] [perdir C:/websites/learn/] pass through C:/websites/learn/javascript/
[subreq] [perdir C:/websites/learn/] pass through C:/websites/learn/javascript/index.html
[subreq] [perdir C:/websites/learn/] pass through C:/websites/learn/javascript/index.htm
[subreq] [perdir C:/websites/learn/] pass through C:/websites/learn/javascript/index.php
Nothing is added to Apache or PHP error log; The browser itself receives status code 200, along with the following response headers
Date: "..."
Server: "Apache/2.4.16 (Win32) PHP/5.6.23"
X-Powered-By: "PHP/5.6.23"
Content-Length: "0"
Keep-Alive: "timeout=5, max=100"
Connection: "Keep-Alive"
Content-Type: "text/html; charset=UTF-8"
The response body is an empty string. Like I said, if I rename the file to index.html the content (vanilla html file) is shown. What could be going on?
I figured it out. That was just me being careless. The problem was with this line from Vhosts config:
php_value auto_prepend_file "C:\websites\learn\noop.php"
More specifically, what was supposed to be a noop was really an execution killer.
noop.php
<?php
exit; // <- exits not just this script but all of PHP and returns to the browser
Once I removed the 2nd line, things were back in order. This also explains why renaming index.php to index.html got things working: it took PHP out of the loop entirely.

Categories