[EtherCard] HTTP me retourne l'erreur 400

Bonjour, je suis nouveau avec la librairie EtherCard, j'utilise actuellement un module Ethernet de typebreakout board ENC28J60
acheter sur eBay.

Il marche bien pour l'instant, je peut faire un ping, crée une page web.

Maintenant je veut pouvoir communiquer avec un serveur PHP sur ma machine pour par exemple sauvegarder des données sur un serveur Mysql.

Le problème est que j'ai une réponse erreur 400 Bad Request.
Voici le code :

#include <EtherCard.h>

static byte mymac[] = {0xDD,0xDD,0xDD,0x00,0x00,0x01};
prog_char website[] = "192.168.100.22";

byte Ethernet::buffer[700];
static uint32_t timer;

static void response_callback (byte status, word off, word len) {
  
  Serial.print((const char*) Ethernet::buffer + off + 207);
}
 
void setup () {
 
  Serial.begin(57600);
  Serial.println("Client Demo");
  Serial.println();
 
  if (!ether.begin(sizeof Ethernet::buffer, mymac, 10))
    Serial.println( "Failed to access Ethernet controller");
 else
   Serial.println("Ethernet controller initialized");
 Serial.println();
 
  if (!ether.dhcpSetup())
    Serial.println("Failed to get configuration from DHCP");
  else
    Serial.println("DHCP configuration done");
 
  ether.printIp("IP Address:\t", ether.myip);
  ether.printIp("Netmask:\t", ether.mymask);
  ether.printIp("Gateway:\t", ether.gwip);
  Serial.println();
  /*
  if (!ether.dnsLookup(website))
    Serial.println("DNS failed");
  else
    Serial.println("DNS resolution done");*/
  ether.hisip[0] = 192;
  ether.hisip[1] = 168;
  ether.hisip[2] = 100;
  ether.hisip[3] = 22;
  ether.printIp("SRV IP:\t", ether.hisip);
  Serial.println();
}
 
void loop() {
 
  ether.packetLoop(ether.packetReceive());
  
  if (millis() > timer) {
    timer = millis() + 5000;
    char postval[] = "id=3";
    ether.httpPost("/test/", website, "", postval,response_callback);
  }
}

et voici le retour du port Serie :

Client Demo

Ethernet controller initialized

DHCP configuration done
IP Address:	192.168.100.100
Netmask:	255.255.255.0
Gateway:	192.168.100.22

SRV IP:	192.168.100.22

DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN">
<html><head>
<title>400 Bad Request</title>
</head><body>
<h1>Bad Request</h1>
<p>Your browser sent a request that this server could not understand.

Request header field is missing ':' separator.

<pre>
àÈêÒà</pre>
</p>
<hr>

Le problème se trouve dans mon code, dans la librairie ou sur mon serveur Apache/PHP ?

Merci
Timiti29

Your browser sent a request that this server could not understand.

Request header field is missing ':' separator.

C'est la requête que tu fais qui n'est pas correcte. Le serveur ne la comprend pas.
Sans doute un problème de syntaxe d'après le message retourné.

J'ai chercher dans les fichier de la librairie, et dans le fichier tcpip.cpp il y a :

static word www_client_internal_datafill_cb(byte fd) {
  BufferFiller bfill = EtherCard::tcpOffset();
  if (fd==www_fd) {
    if (client_postval == 0) {
      bfill.emit_p(PSTR("GET $F$S HTTP/1.0\r\n"
                        "Host: $F\r\n"
                        "$F\r\n"
                        "\r\n"), client_urlbuf,
                                 client_urlbuf_var,
                                 client_hoststr, client_additionalheaderline);
    } else {
      prog_char* ahl = client_additionalheaderline;
      bfill.emit_p(PSTR("POST $F HTTP/1.0\r\n"
                        "Host: $F\r\n"
                        "$F$S"
                        "Accept: */*\r\n"
                        "Content-Length: $D\r\n"
                        "Content-Type: application/x-www-form-urlencoded\r\n"
                        "\r\n"
                        "$S"), client_urlbuf,
                                 client_hoststr,
                                 ahl != 0 ? ahl : PSTR(""),
                                 ahl != 0 ? "\r\n" : "",
                                 strlen(client_postval),
                                 client_postval);
    }
  }
  return bfill.position();
}

Je ne connais pas la structure des requetes HTTP
Il y a une erreur dans le code ?
Merci
Timiti29

Bonjour,
Tu envoie quoi exactement dans ta requête?
À voir le code tu envoie une requête style
192.168.100.22/test/id=3
Ça veut rien dire ça. Aucun fichier demandé
Pourquoi le server ip à la même ip que le gateway?
As tu teste de faire la même requête avec ton Pc?

Re,
dsl petit oublie de ma part, j'avais oublier le index.php je lais mis mais je n'est aucun changement
sur mon serveur j'ai une page à l'adresse http://192.168.100.22/test/index.php

je dispose d'un ordinateur portable ayant une connexion wifi à internet (sur un hotspot public)
et j'ai brancher mon ENC28J60 sur un switch ainsi que mon pc portable.

J'ai configurer l'interface, et j'ai activer le routage sur linux.
c'est pourquoi l'adresse de la passerelle est celle de mon pc portable.
cependant comme j'essaye de rester en local cela ne devrais pas avoir de conséquence.

Voici mon code :

#include <EtherCard.h>

static byte mymac[] = {0xDD,0xDD,0xDD,0x00,0x00,0x01};
prog_char website[] = "192.168.100.22";

byte Ethernet::buffer[700];
static uint32_t timer;

static void response_callback (byte status, word off, word len) {
  
  Serial.print((const char*) Ethernet::buffer + off + 207);
}
 
void setup () {
 
  Serial.begin(57600);
  Serial.println("Client Demo");
  Serial.println();
 
  if (!ether.begin(sizeof Ethernet::buffer, mymac, 10))
    Serial.println( "Failed to access Ethernet controller");
 else
   Serial.println("Ethernet controller initialized");
 Serial.println();
 
  if (!ether.dhcpSetup())
    Serial.println("Failed to get configuration from DHCP");
  else
    Serial.println("DHCP configuration done");
 
  ether.printIp("IP Address:\t", ether.myip);
  ether.printIp("Netmask:\t", ether.mymask);
  ether.printIp("Gateway:\t", ether.gwip);
  Serial.println();
  /*
  if (!ether.dnsLookup(website))
    Serial.println("DNS failed");
  else
    Serial.println("DNS resolution done");*/
  ether.hisip[0] = 192;
  ether.hisip[1] = 168;
  ether.hisip[2] = 100;
  ether.hisip[3] = 22;
  ether.printIp("SRV IP:\t", ether.hisip);
  Serial.println();
}
 
void loop() {
 
  ether.packetLoop(ether.packetReceive());
  
  if (millis() > timer) {
    timer = millis() + 5000;
    char postval[] = "id=3";
    ether.httpPost("/test/index.php", website, "", postval,response_callback);
  }
}

J'essaye de faire une requete POST sur le fichier index.php du dossier test avec un parametre id ayant comme valeur un nombre ici 3 par exemple.

Comment je peut tester une requete POST en local ?

Merci
Timiti29

Avec ton navigateur et tu mets l'adresse de ton fichier en local.

char postval[] = "id=3";

ne devrait pas plutôt être ça

char postval[] = "?id=3";

Évidement que sa marche en fessant un http://localhost/test/index.php
c'est comme sa que je test un script php avant d'utiliser l'arduino.

voici mon script php pour les curieux :

<!DOCTYPE html>
<html>
<head> 
        <meta charset="utf-8" />
</head>
<body> 
<?php 
        if(isset($_POST["id"]) && !empty($_POST["id"]))
                echo "Id : " + $_POST["id"];
        else
                echo "Nothing to show"; 
?>
</body>
</html>

Merci
Timiti29

Edit : j'ai modifier et ajouter le '?' qu'il devais manquer, mais cela ne change pas le message d'erreur

@jf: en tappant dans la barre du navigateur, tu fais un GET pas un POST

@fduf: la syntaxe est bonne pour post. Le ? est pour get.

@timiti essaye avec du get au lieu de post
http://192.168.100.22/test/index.php?id=3

Edit: il faut modifier ton php pour fonctionner en get. De mémoire il y a des variables qui marchent aussi bien en post qu'en get.

Le script en lui même fonctionne aussi bien avec GET que POST.
cependant, avec l'arduino le problème reste le même que sa soit en GET ou en POST

voici mon script arduino en POST : (je ne mais que la fonction loop car il n'y a quelle qui change)

void loop() {
 
  ether.packetLoop(ether.packetReceive());
  
  if (millis() > timer) {
    timer = millis() + 5000;
    char postval[] = "id=3";
    ether.httpPost("/test/index.php", website, "", postval,response_callback);
  }
}

Et avec un GET :

void loop() {
 
  ether.packetLoop(ether.packetReceive());
  
  if (millis() > timer) {
    timer = millis() + 5000;
    char postval[] = "?id=3";
    ether.browseUrl("/test/index.php", postval, website,response_callback);
  }
}

Le résultat est exactement le même au niveau du retour (Serie) de l'arduino

Merci
Timiti29

Edit : Que je script php et l'arduino fonctionne en GET ou en POST, qu'il y est des variables ou pas, je devrais au moins avoir un message 200 avec ma page html

Y'a plus qu'a faire un peu de tcpdump pour comprendre ce qui se passe.

Désolé mais j'utilise Ethernet avec un wiz et je ne connais pas les subtilités de EtherCard.

voici le résultat d'un "sudo tcpdump -i eth1 -vn"

12:02:00.071522 IP (tos 0x0, ttl 64, id 0, offset 0, flags [DF], proto UDP (17), length 298)
    0.0.0.0.68 > 255.255.255.255.67: BOOTP/DHCP, Request from dd:dd:dd:00:00:01, length 270, xid 0x42000000, Flags [none]
	  Client-Ethernet-Address dd:dd:dd:00:00:01
	  Vendor-rfc1048 Extensions
	    Magic Cookie 0x63825363
	    DHCP-Message Option 53, length 1: Discover
	    Client-ID Option 61, length 7: ether dd:dd:dd:00:00:01
	    Hostname Option 12, length 10: "Arduino-01"
	    Parameter-Request Option 55, length 3: 
	      Subnet-Mask, Default-Gateway, Domain-Name-Server
12:02:00.071880 IP (tos 0x10, ttl 128, id 0, offset 0, flags [none], proto UDP (17), length 328)
    192.168.100.22.67 > 192.168.100.100.68: BOOTP/DHCP, Reply, length 300, xid 0x42000000, Flags [none]
	  Your-IP 192.168.100.100
	  Server-IP 192.168.100.22
	  Client-Ethernet-Address dd:dd:dd:00:00:01
	  Vendor-rfc1048 Extensions
	    Magic Cookie 0x63825363
	    DHCP-Message Option 53, length 1: Offer
	    Server-ID Option 54, length 4: 192.168.100.22
	    Lease-Time Option 51, length 4: 600
	    Subnet-Mask Option 1, length 4: 255.255.255.0
	    Default-Gateway Option 3, length 4: 192.168.100.22
	    Domain-Name-Server Option 6, length 4: 192.168.100.22
12:02:00.075312 IP (tos 0x0, ttl 64, id 0, offset 0, flags [DF], proto UDP (17), length 310)
    192.168.100.100.68 > 255.255.255.255.67: BOOTP/DHCP, Request from dd:dd:dd:00:00:01, length 282, xid 0x42000000, Flags [none]
	  Client-Ethernet-Address dd:dd:dd:00:00:01
	  Vendor-rfc1048 Extensions
	    Magic Cookie 0x63825363
	    DHCP-Message Option 53, length 1: Request
	    Client-ID Option 61, length 7: ether dd:dd:dd:00:00:01
	    Hostname Option 12, length 10: "Arduino-01"
	    Requested-IP Option 50, length 4: 192.168.100.100
	    Server-ID Option 54, length 4: 192.168.100.22
	    Parameter-Request Option 55, length 3: 
	      Subnet-Mask, Default-Gateway, Domain-Name-Server
12:02:00.075568 IP (tos 0x10, ttl 128, id 0, offset 0, flags [none], proto UDP (17), length 328)
    192.168.100.22.67 > 192.168.100.100.68: BOOTP/DHCP, Reply, length 300, xid 0x42000000, Flags [none]
	  Your-IP 192.168.100.100
	  Server-IP 192.168.100.22
	  Client-Ethernet-Address dd:dd:dd:00:00:01
	  Vendor-rfc1048 Extensions
	    Magic Cookie 0x63825363
	    DHCP-Message Option 53, length 1: ACK
	    Server-ID Option 54, length 4: 192.168.100.22
	    Lease-Time Option 51, length 4: 600
	    Subnet-Mask Option 1, length 4: 255.255.255.0
	    Default-Gateway Option 3, length 4: 192.168.100.22
	    Domain-Name-Server Option 6, length 4: 192.168.100.22
12:02:04.812186 ARP, Ethernet (len 6), IPv4 (len 4), Request who-has 192.168.100.22 tell 192.168.100.100, length 46
12:02:04.812209 ARP, Ethernet (len 6), IPv4 (len 4), Reply 192.168.100.22 is-at 00:10:60:59:2d:19, length 28
12:02:04.813440 IP (tos 0x0, ttl 64, id 0, offset 0, flags [DF], proto TCP (6), length 44)
    192.168.100.100.2850 > 192.168.100.22.80: Flags [S], cksum 0x3977 (correct), seq 2560, win 768, options [mss 550], length 0
12:02:04.813488 IP (tos 0x0, ttl 64, id 0, offset 0, flags [DF], proto TCP (6), length 44)
    192.168.100.22.80 > 192.168.100.100.2850: Flags [S.], cksum 0x49ea (incorrect -> 0x26c9), seq 3729914548, ack 2561, win 14600, options [mss 1460], length 0
12:02:04.814515 IP (tos 0x0, ttl 64, id 0, offset 0, flags [DF], proto TCP (6), length 40)
    192.168.100.100.2850 > 192.168.100.22.80: Flags [.], cksum 0x738e (correct), ack 1, win 1024, length 0
12:02:04.817815 IP (tos 0x0, ttl 64, id 0, offset 0, flags [DF], proto TCP (6), length 572)
    192.168.100.100.2850 > 192.168.100.22.80: Flags [P.], cksum 0x35c3 (correct), seq 1:533, ack 1, win 1024, length 532
12:02:04.817846 IP (tos 0x0, ttl 64, id 53891, offset 0, flags [DF], proto TCP (6), length 40)
    192.168.100.22.80 > 192.168.100.100.2850: Flags [.], cksum 0x49e6 (incorrect -> 0x3936), ack 533, win 15428, length 0
12:02:04.818085 IP (tos 0x0, ttl 64, id 53892, offset 0, flags [DF], proto TCP (6), length 552)
    192.168.100.22.80 > 192.168.100.100.2850: Flags [.], cksum 0x4be6 (incorrect -> 0x77d8), seq 1:513, ack 533, win 15428, length 512
12:02:04.818101 IP (tos 0x0, ttl 64, id 53893, offset 0, flags [DF], proto TCP (6), length 180)
    192.168.100.22.80 > 192.168.100.100.2850: Flags [P.], cksum 0x4a72 (incorrect -> 0x7762), seq 513:653, ack 533, win 15428, length 140
12:02:04.818151 IP (tos 0x0, ttl 64, id 53894, offset 0, flags [DF], proto TCP (6), length 40)
    192.168.100.22.80 > 192.168.100.100.2850: Flags [F.], cksum 0x49e6 (incorrect -> 0x36a9), seq 653, ack 533, win 15428, length 0
12:02:04.861887 IP (tos 0x0, ttl 64, id 53892, offset 0, flags [DF], proto TCP (6), length 40)
    192.168.100.100.2850 > 192.168.100.22.80: Flags [FP.], cksum 0x6f71 (correct), seq 533, ack 513, win 1024, length 0
12:02:04.861949 IP (tos 0x0, ttl 64, id 53895, offset 0, flags [DF], proto TCP (6), length 40)
    192.168.100.22.80 > 192.168.100.100.2850: Flags [.], cksum 0x49e6 (incorrect -> 0x36a8), ack 534, win 15428, length 0
12:02:04.863191 IP (tos 0x0, ttl 64, id 53893, offset 0, flags [DF], proto TCP (6), length 40)
    192.168.100.100.2850 > 192.168.100.22.80: Flags [.], cksum 0x6eee (correct), ack 653, win 1024, length 0
12:02:04.863217 IP (tos 0x0, ttl 64, id 53896, offset 0, flags [DF], proto TCP (6), length 40)
    192.168.100.22.80 > 192.168.100.100.2850: Flags [.], cksum 0x49e6 (incorrect -> 0x36a8), ack 534, win 15428, length 0
12:02:04.864105 IP (tos 0x0, ttl 64, id 53894, offset 0, flags [DF], proto TCP (6), length 40)
    192.168.100.100.2850 > 192.168.100.22.80: Flags [FP.], cksum 0x6ee4 (correct), seq 533, ack 654, win 1024, length 0

Je ne sais pas si sa peut t'aider, je ne voit pas ou ce trouve la requete GET.
Merci
Timiti29

met à plat tes logs apache

cd /var/log/apache2

access.log
error.log

relance ta requete et mets le contenu de ton error.log ici
ca sera plus simple pour trouver l'erreur
mais je crois qu'il manque quelque chose dans ton script
style ether.tcpSend ou ether.browseURL

Il y a déjà un ether.browseUrl c'est d'ailleurs presque la seule ligne
J'ai vidée les log, et modifier mon programme pour qu'il exécute une seule foit la fonction ether.browseUrl
Voici le fichier access.log :

192.168.100.100 - - [20/Oct/2013:12:58:53 +0200] "GET \xb3\xe0\x01\xc0\x1d\x92\xab4\xb1\x07\xe1\xf7\x12\xe0\xcc\xeb\xd2\xe0 HTTP/1.0" 400 652 "-" "-"

et error.log :

[Sun Oct 20 12:58:53 2013] [error] [client 192.168.100.100] request failed: error reading the headers

Merci
Timiti29

étrange, t'as pas le nom du fichier indiqué en referer dans error.log

tu as quoi comme distri et apache?
mod_rewrite activé?
fichier .htacces?

je viens de regarder les exemples d'EtherCard et ca ne ressemble pas trop à ce que tu fais

if (!ether.dnsLookup(website))
Serial.println("DNS failed");

ether.printIp("SRV: ", ether.hisip);
}

void loop () {
ether.packetLoop(ether.packetReceive());

if (millis() > timer) {
timer = millis() + 5000;
Serial.println();
Serial.print("<<< REQ ");
ether.browseUrl(PSTR("/foo/"), "bar", website, my_callback);
}

Tes chaines de caracteres ne sont pas bonnes
Regarde les protypes des fonctions utilisées : prog_char doit etre du type PSTR

J'ai enlever le PSTR car il me fessait une erreur :

lucadentella_it_test3.ino: In function ‘void loop()’:
lucadentella_it_test3.ino:59:80: error: invalid conversion from ‘const char*’ to ‘prog_char* {aka char*}’ [-fpermissive]
In file included from lucadentella_it_test3.ino:1:0:
/usr/share/arduino/libraries/EtherCard/EtherCard.h:173:15: error:   initializing argument 1 of ‘static void EtherCard::browseUrl(prog_char*, const char*, prog_char*, void (*)(uint8_t, uint16_t, uint16_t))’ [-fpermissive]

Merci
Timiti29
PS : j'utilise Kubuntu 13.04
et je n'ai pas de lien vers le mod rewrite dans le dossier /etc/apache2/mod-enabled

Edit : j'ai essayer en stockant avant les données dans des variable prog_char mais j'ai toujours l'erreur 400 et les même erreur dans le fichier access.log et error.log

#include <EtherCard.h>

static byte mymac[] = {0xDD,0xDD,0xDD,0x00,0x00,0x01};
prog_char website[] = "192.168.100.22";

boolean x = true;

byte Ethernet::buffer[700];
static uint32_t timer;

static void response_callback (byte status, word off, word len) {
  
  Serial.print((const char*) Ethernet::buffer + off + 207);
}
 
void setup () {
 
  Serial.begin(57600);
  Serial.println("Client Demo");
  Serial.println();
 
  if (!ether.begin(sizeof Ethernet::buffer, mymac, 10))
    Serial.println( "Failed to access Ethernet controller");
 else
   Serial.println("Ethernet controller initialized");
 Serial.println();
 
  if (!ether.dhcpSetup())
    Serial.println("Failed to get configuration from DHCP");
  else
    Serial.println("DHCP configuration done");
 
  ether.printIp("IP Address:\t", ether.myip);
  ether.printIp("Netmask:\t", ether.mymask);
  ether.printIp("Gateway:\t", ether.gwip);
  Serial.println();
  /*
  if (!ether.dnsLookup(website))
    Serial.println("DNS failed");
  else
    Serial.println("DNS resolution done");*/
  ether.hisip[0] = 192;
  ether.hisip[1] = 168;
  ether.hisip[2] = 100;
  ether.hisip[3] = 22;
  ether.printIp("SRV IP:\t", ether.hisip);
  Serial.println("Loop :");
  delay(1000);
}
 
void loop() {
 
  ether.packetLoop(ether.packetReceive());
  
  if ((millis() > timer) && x == true) {
    timer = millis() + 5000;
    prog_char url[] = "/test/index.php";
    prog_char postval[] = "?id=3";
    //ether.httpPost("/test/index.php", website, "", postval,response_callback);
    ether.browseUrl(url, postval, website,response_callback);
    x = false;
  }
}

Tous les exemples sur internet montrent qu'il faut utiliser PSTR
De plus le log apache montre bien que l'url envoyé est n'importe quoi parce que la lib va chercher en mémoire flash alors que tu lui passe une adresse en RAM

Regarde mieux les examples
Par exemple utilise PSTR("/test/") au lieu de "test"

Je vient de dire que j'ai déjà essayer et que j'ai un message d' erreur qui me dit qu'il ne peut pas convertir un const char en prog_char

Je lais mis dans mon dernier message.

merci

Timiti29