wordermorr wordermorr - 10 days ago 14
PHP Question

Error 406 Not Acceptable with idHTTP on Android

I'm trying to post a insert on a MySQL database using idHTTP and a PHP script. This is the PHP script to insert in the database:

$mysqli = new mysqli($servidor, $usuario, $senha, $banco);

// Caso algo tenha dado errado, exibe uma mensagem de erro
if (mysqli_connect_errno()) trigger_error(mysqli_connect_error());

$iduser = quoted_printable_decode($_POST['iduser']);
$nome = quoted_printable_decode($_POST['nome']);
$data = quoted_printable_decode($_POST['data']);
$hora = quoted_printable_decode($_POST['hora']);
$mensagem = quoted_printable_decode($_POST['mensagem']);
$latitude = quoted_printable_decode($_POST['latitude']);
$longitude = quoted_printable_decode($_POST['longitude']);
$imagem = $_FILES["imagem"]['tmp_name'];
$tamanho = $_FILES['imagem']['size'];

header($_SERVER["SERVER_PROTOCOL"] . " 200 OK");
header('Content-Type: text/plain; charset="utf-8"');

if ( $imagem != "none" )
{
$fp = fopen($imagem, "rb");
$conteudo = fread($fp, $tamanho);
$conteudo = addslashes($conteudo);
fclose($fp);

$queryInsercao = "INSERT INTO tabpainel (iduser, nome, data, hora, mensagem, latitude, longitude, imagem) VALUES ('$iduser', '$nome', '$data','$hora','$mensagem', '$latitude', '$longitude', '$conteudo')";

mysqli_query($mysqli,$queryInsercao) or die("Algo deu errado ao inserir o registro. Tente novamente.");

if (mysqli_affected_rows($mysqli) > 0)
include 'baixarpainel.php';
else
print utf8_encode("Não foi possível inserir o registro");
}
else
print utf8_encode("Não foi possível carregar a imagem.");
?>


And in Delphi, i'm using this:

FormPHP := TIdMultiPartFormDataStream.Create;

FormPHP.AddFile ('imagem', AImagem, 'image/jpeg');
FormPHP.AddFormField ('iduser', AIDUser, 'utf-8');
FormPHP.AddFormField ('nome', ANome, 'utf-8');
FormPHP.AddFormField ('data', AData, 'utf-8');
FormPHP.AddFormField ('hora', AHora, 'utf-8');
FormPHP.AddFormField ('mensagem', AMensagem, 'utf-8');
FormPHP.AddFormField ('latitude', '1');
FormPHP.AddFormField ('longitude', '1');

Response := TStringStream.Create('',TEncoding.UTF8);

HTTP:= TIdHTTP.Create(self);
HTTP.Post('http://addressexample.com/cadastro.php',FormPHP,Response);


It was working fine until a had to change the hosting company. With Hostinger was ok but with Hostgator it doesn't. With Hostgator the idHTTP raise an exception in the class EIdHTTPProtocalException with the message: "HTTP/1.1 406 Not Acceptable". The Hostgator support has already disabled the mod_security, that could cause the problem.

This exception only occurs on Android. Using the same app on Windows, it works fine.

Answer

TIdHTTP works exactly the same way on all platforms, as Indy uses a single cross-platform codebase. So the generated HTTP request should be exactly the same on all platforms.

An HTTP 406 error happens when the HTTP request includes an Accept header that does not specify any media type that the server is capable of rendering the response in. Per RFC 2616 Section 14.1:

If no Accept header field is present, then it is assumed that the client accepts all media types. If an Accept header field is present, and if the server cannot send a response which is acceptable according to the combined Accept field value, then the server SHOULD send a 406 (not acceptable) response.

Your PHP script is sending a text/plain response, so if you send an Accept header that does not allow text/plain then that can cause a 406 error. It sounds like Hostgator is enforcing that more than Hostinger does.

By default, TIdHTTP sets its Request.Accept property to the following string value:

'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8'

Which technically allows all media types via */*, but just with a lower priority than some other media types. But that default should still be enough to allow a text/plain response, if the server implements Accept handling correctly.

You need to contact Hostgator and discuss the issue with them, as the problem is on their end, not yours.

That being said, since you know the server response is always text/plain, you could just add the following to your code before calling Post():

HTTP.Request.Accept := 'text/plain';
HTTP.Request.AcceptCharset := 'utf-8';