Getting HTTP Error 400 when trying to send json output

1. Caddy version (caddy version):

v2.5.1

2. How I run Caddy:

a. System environment:

Ubuntu 22.04 (Linux deafkid-dedi 5.15.0-33-generic #34-Ubuntu SMP Wed May 18 13:34:26 UTC 2022 x86_64 x86_64 x86_64 GNU/Linux)

b. Command:

systemctl start caddy

c. Service/unit/compose file:

[Unit]
Description=Caddy
Documentation=https://caddyserver.com/docs/
After=network.target network-online.target
Requires=network-online.target

[Service]
Type=notify
User=caddy
Group=caddy
ExecStart=/usr/bin/caddy run --environ --config /etc/caddy/Caddyfile
ExecReload=/usr/bin/caddy reload --config /etc/caddy/Caddyfile
TimeoutStopSec=5s
LimitNOFILE=1048576
LimitNPROC=512
PrivateTmp=true
ProtectSystem=full
AmbientCapabilities=CAP_NET_BIND_SERVICE

[Install]
WantedBy=multi-user.target

d. My complete Caddyfile or JSON config:

{
        admin off
}
(logging) {
        log {
                output file /var/log/caddy/caddy.log {
                        roll_size 15mb
                        roll_keep 20
                }
        }
}
(php) {
        php_fastcgi unix//run/php/php8.1-fpm.sock
}
deafkid.dev {
        import logging
        import php
        root * /var/www/deafkid.dev
        file_server
}
db.deafkid.dev {
        import logging
        import php
        root * /usr/share/phpmyadmin
        file_server
}
panel.deafkid.dev {
        import logging
        php_fastcgi unix//run/php/php8.0-fpm.sock
        root * /var/www/pterodactyl/public
        file_server
        header X-Content-Type-Options nosniff
        header X-XSS-Protection "1; mode=block"
        header X-Robots-Tag none
        header Content-Security-Policy "frame-ancestors 'self'"
        header X-Frame-Options DENY
        header Referrer-Policy same-origin
        request_body {
                max_size 100m
        }
        respond /.ht* 403
}
git.deafkid.dev {
        reverse_proxy localhost:3000
}
media.deafkid.dev {
        import logging
        import php
        root * /var/www/media.deafkid.dev
        file_server
}

3. The problem I’m having:

When visiting https://media.deafkid.dev/upload.php, I should be expecting a JSON body when visiting the browser or using curl (with error status 400) - see below:

Expected behaviour (https://focusvity.me/upload.php (hosting on a different server using Apache)):

C:\Users\natha>curl -v https://focusvity.me/upload.php
*   Trying 104.21.28.70:443...
* Connected to focusvity.me (104.21.28.70) port 443 (#0)
* schannel: disabled automatic use of client certificate
* schannel: ALPN, offering http/1.1
* schannel: ALPN, server accepted to use http/1.1
> GET /upload.php HTTP/1.1
> Host: focusvity.me
> User-Agent: curl/7.79.1
> Accept: */*
>
* Mark bundle as not supporting multiuse
< HTTP/1.1 400 Bad Request
< Date: Sun, 29 May 2022 03:42:39 GMT
< Content-Type: application/json
< Content-Length: 53
< Connection: keep-alive
< CF-Cache-Status: DYNAMIC
< Expect-CT: max-age=604800, report-uri="https://report-uri.cloudflare.com/cdn-cgi/beacon/expect-ct"
< Report-To: {"endpoints":[{"url":"https:\/\/a.nel.cloudflare.com\/report\/v3?s=L34nvpmLBMJVlxL%2B5J0vvzZ%2B0rhQIMRMaGkLQ3uPGJ2jtiilT8Q8xvp51vwHi52qbfA%2FAMuu4KoDOlQfG6lUGEiE3zs1koi8NurdoDGA6JO1w7GlRsV3dMNnWoWeeRI%3D"}],"group":"cf-nel","max_age":604800}
< NEL: {"success_fraction":0,"report_to":"cf-nel","max_age":604800}
< Server: cloudflare
< CF-RAY: 712c38aa1d488b41-HKG
< alt-svc: h3=":443"; ma=86400, h3-29=":443"; ma=86400
<
{"status":"ERROR","errormsg":"No post data received"}* Connection #0 to host focusvity.me left intact

Current behaviour (https://media.deafkid.dev.upload.php):

C:\Users\natha>curl -v https://media.deafkid.dev/upload.php
*   Trying 144.76.119.187:443...
* Connected to media.deafkid.dev (144.76.119.187) port 443 (#0)
* schannel: disabled automatic use of client certificate
* schannel: ALPN, offering http/1.1
* schannel: ALPN, server accepted to use http/1.1
> GET /upload.php HTTP/1.1
> Host: media.deafkid.dev
> User-Agent: curl/7.79.1
> Accept: */*
>
* Mark bundle as not supporting multiuse
< HTTP/1.1 400 Bad Request
< Content-Type: application/json
< Server: Caddy
< Status: 400 Bad Request
< Date: Sun, 29 May 2022 03:44:10 GMT
< Content-Length: 0
<
* Connection #0 to host media.deafkid.dev left intact

upload.php file:

<?php

error_reporting(E_ERROR);
header('Content-Type: application/json');
$tokens = array("REDACTED");

function generateHash() {
    $keys = array_merge(range(0, 9), range('a', 'z'));
    for ($i = 0; $i < 8; $i++) {
        $key .= $keys[mt_rand(0, count($keys) - 1)];
    }
    return $key;
}

if (isset($_POST['secret'])) {
    if (in_array($_POST['secret'], $tokens)) {
        $filename = generateHash();
        $target_file = $_FILES["sharex"]["name"];
        $fileType = pathinfo($target_file, PATHINFO_EXTENSION);
        if (move_uploaded_file($_FILES["sharex"]["tmp_name"], $filename . '.' . $fileType)) {
            http_response_code(200);
            $json->status = "OK";
            $json->errormsg = "";
            $json->url = $filename . '.' . $fileType;
            echo json_encode($json);
            return;
        } else {
            http_response_code(400);
            $json->status = "ERROR";
            $json->errormsg = "Cannot upload file";
            echo json_encode($json);
            return;
        }
    } else {
      http_response_code(401);
      $json->status = "ERROR";
      $json->errormsg = "Incorrect secret token";
      echo json_encode($json);
      return;
    }
} else {
    http_response_code(400);
    $json->status = "ERROR";
    $json->errormsg = "No post data received";
    echo json_encode($json);
    return;
}

 ?>

4. Error messages and/or full log output:

No errors

5. What I already tried:

I have tried removing the http_response_code lines from the file but I ended up getting an internal server error (500) when loading the page or using curl. I asked a friend that knows a bit of Caddy but he’s unsure how to fix the error and referred me here to get some assistance.

6. Links to relevant resources:

N/A Getting HTTP Error 400 when trying to send json output

1 Like

Hi Nathan, welcome to the forum.

Your first example was actually served by Cloudflare, not Apache. Maybe that doesn’t matter, as it looks like it wasn’t cached, but I’m curious what a direct request to the Apache server would look like.

What was the 500 error specifically when you removed the http_response_code line?

What are you seeing in Caddy’s logs? Turn on the debug global option to see more details.

I don’t think this is a problem with Caddy, it seems like it would be a problem with your PHP script or PHP-FPM setup.

Small thing, I’d recommend writing these like this, putting them all in a single header handler; it’s very slightly more efficient, and I think it reads nicer:

	header {
		X-Content-Type-Options nosniff
		X-XSS-Protection "1; mode=block"
		X-Robots-Tag none
		Content-Security-Policy "frame-ancestors 'self'"
		X-Frame-Options DENY
		Referrer-Policy same-origin
	}
2 Likes

Hey guys, my apologies. I should’ve done more testing with my PHP code - it turns out PHP doesn’t like variable->key anymore.

There isn’t any problem with Caddy on my end. Thanks for the help, though.

While the page is being served by Cloudflare, the VPS is using Apache to run PHP pages. If you are still curious about what the direct request to the Apache server would look like, I have attached the curl result:

C:\Users\natha>curl -v http://localhost/image/upload.php
*   Trying 127.0.0.1:80...
* Connected to localhost (127.0.0.1) port 80 (#0)
> GET /image/upload.php HTTP/1.1
> Host: localhost
> User-Agent: curl/7.79.1
> Accept: */*
>
* Mark bundle as not supporting multiuse
< HTTP/1.1 400 Bad Request
< Date: Sun, 29 May 2022 06:29:05 GMT
< Server: Apache/2.4.53 (Win64) OpenSSL/1.1.1n PHP/8.1.4
< X-Powered-By: PHP/8.1.4
< Content-Length: 53
< Connection: close
< Content-Type: application/json
<
{"status":"ERROR","errormsg":"No post data received"}* Closing connection 0```

I think it’s moreso that PHP will not initialize an object out of thin air anymore, you need to do $json = new stdClass; first to initialize that variable.

Or you can just make an array and JSON encode that instead, like json_encode(["status" => "ERROR", "errormsg" => "whatever"])

1 Like