FULL-C: http client functions: Porovnání verzí

Řádek 211: Řádek 211:
  
 
Obsah Content-Type je možné změnit pomocí funkce http_header_set_content_type().
 
Obsah Content-Type je možné změnit pomocí funkce http_header_set_content_type().
 +
 +
Nastavená hodnota zůstává až do další změny touto funkcí. Na výchozí hodnotu (text/plain) je nastavena jedině vždy při startu nového (nebo restartu stejného) FC programu.
  
 
Zadejte čistě text parametru, příklad (bez uvozovek): "application/json" - tedy čistě to co je až za dvoutečkou, a bez ukončovacích znaků !
 
Zadejte čistě text parametru, příklad (bez uvozovek): "application/json" - tedy čistě to co je až za dvoutečkou, a bez ukončovacích znaků !
Řádek 221: Řádek 223:
 
'''Pozor''' na maximální omezení délky tohoto textu (64 znaků).
 
'''Pozor''' na maximální omezení délky tohoto textu (64 znaků).
  
'''Pozor''' - tato položka je vložena jen do HTTP-POST hlavičky, kam správně patří (protože POST má i svůj datový obsah, který se z SDS odesílá). Naopak hlavička HTTP-GET tento prvek neobsahuje (protože se jedná čistě o dotaz). Pokud chcete určit, jaký obsahový typ má přijít v odpovědi na HTTP-GET dotaz, musíte použít tag "Accept: ...", který lze do hlavičky vložit následující funkcí.
+
'''Pozor''' - tato položka (Content-Type) je vložena '''jen''' do HTTP-POST hlavičky, kam správně patří (protože POST má i svůj datový obsah, který se z SDS odesílá, a jeho typ se právě takto popisuje).  
 +
 
 +
Naopak hlavička HTTP-GET tento prvek '''neobsahuje''' (protože u GET se jedná čistě o dotaz). Pokud chcete určit, jaký obsahový typ má přijít v odpovědi na HTTP-GET dotaz, musíte použít tag "Accept: ...", který lze do hlavičky vložit následující funkcí.
  
Tedy ještě jednou - je to častá neznalost RFC pro HTTP komunikaci - pokud chcete určit jaký formát odpovědi má ze serveru přijít, dělá se to pomocí Accept (viz [https://www.rfc-editor.org/rfc/rfc9110.html#name-content-negotiation-fields RFC9110], a nikoliv pomocí Content-Type !!!
+
Tedy ještě jednou - je to častá neznalost RFC pro HTTP komunikaci - pokud chcete určit jaký formát odpovědi má ze serveru přijít, dělá se to pomocí Accept (viz [https://www.rfc-editor.org/rfc/rfc9110.html#name-content-negotiation-fields RFC9110]), a nikoliv pomocí Content-Type !!!
  
 
==== Přidání dalšího uživatelského řádku do hlavičky ====
 
==== Přidání dalšího uživatelského řádku do hlavičky ====
  
Pomocí funkce http_header_set_user_row() lze přidat jeden celý vlastní řádek.
+
Pomocí funkce http_header_set_user_row() lze přidat jeden celý vlastní řádek. Tento řádek je přidán jak do HTTP-GET tak do HTTP-POST požadavků, odesílaných příslušnou FULL-C funkcí. Nastavená hodnota zůstává až do další změny touto funkcí (nebo až do nahrání nového FC programu, kde je při startu nového FC programu vždy tento nastavený obsah odstraněn).
  
 
Například:
 
Například:
Řádek 242: Řádek 246:
 
Tato funkce očekává celkový text plného řádku, ale pozor - bez ukončovacích znaků atd. - viz příklad výše.
 
Tato funkce očekává celkový text plného řádku, ale pozor - bez ukončovacích znaků atd. - viz příklad výše.
  
Pozor na maximální délku textu, který lze do hlavičky vložit (128 znaků).
+
Pozor na maximální délku textu, který lze do hlavičky vložit (128 znaků). V současném FW lze vložit jen jeden uživatelský řádek (lze si ale pomoct trikem, pokud se vám více řádků vleze do celkového délkového omezení, tak to snadno řešit lze).
  
 
==== Návratové hodnoty pro obě tyto funkce ====
 
==== Návratové hodnoty pro obě tyto funkce ====

Verze z 8. 3. 2023, 19:36

Tato stránka popisuje programovací jazyk FULL-C, který je dostupný na vybraných zařízeních SDS. 
Některá zařízení používají SDS-C, pro který máme návody jinde na této WiKi.

Síťové funkce: komunikace s webovým serverem

Zařízení SDS umožňuje odeslat HTTP-GET a HTTP-POST dotaz na zvolený HTTP server. FULL-C program určuje cílový server (IP adresu a Host název), a současně určuje obsah (Body) v dotazu.

Za tímto účelem jsou k dispozici tyto dvě funkce:

         void http_get(unsigned int IP0, unsigned int IP1, unsigned int IP2, unsigned int IP3, unsigned int Port, char *HostName, char *GETtext, void *ReceiveDataBuffer, unsigned int MaximalReceiveDataLength);
 unsigned int http_get_status(unsigned int *httpResponseValue, unsigned int *receivedDataSize);

Dále je možné poslat HTTP-POST požadavek, prakticky stejným způsobem:

         void http_post(unsigned int IP0, unsigned int IP1, unsigned int IP2, unsigned int IP3, unsigned int Port,                         
                        char *HostName, char *GETtext, void *ReceiveDataBuffer, unsigned int MaximalReceiveDataLength, char *POSTtext);

Před odesláním HTTP-GET nebo HTTP-POST, lze do HTTP hlavičky přidat vlastní definovaný řádek:

         int http_header_set_user_row(unsigned int reserved, char * text);

Před odesláním HTTP-POST, lze provést změnu konfigurace odeslané HTTP-POST hlavičky:

         int http_header_set_content_type(char * value);

Probíhající get/post požadavek lze z FULL-C programu (předčasně) ukončit:

         void http_close(void);


Princip

SDS po zavolání funkce http_get() se SDS spojí s webovým serverem na zadané IP adrese a předá tomuto serveru GET požadavek. Odpověď je pak v SDS zpracována a předána FULL-C programu.

Pro kontrolu průběhu a úspěchu či chyby, je k dispozici funkce http_get_status().

Funkce http_get() se typicky kombinuje s funkcí dns_resolv(), kdy jako uživatel pouze znáte HostName, a potřebujete nejprve získat aktuální hodnotu IP adresu serveru, před zavoláním http_get().


Upozornění

Všechny funkce (http_get / http_post) pro svou práci potřebují určité volné místo v pracovní paměti (heap). Pokud toto místo není k dispozici, funkce nejsou provedeny (ohlášena chyba 1034). Je na vás zajistit, aby tam to místo bylo.

Potřebná velikost paměti odpovídá celému datovému obsahu (http hlavička + get/post texty), který se odesílá do serveru. Paměť si funkce alokuje sama, interně. Po dokončení odesílání je tato paměť automaticky uvolněna.


Příklad #1: HTTP GET

V tomto příkladu komunikuje SDS s webovým serverem na adrese 192.168.1.110 na TCP portu 80, a pokud se vše povede, tak vypíše do konzole i přijatou odpověď (o délce MaximalReceiveDataLength bajtů).

void main(void)
{
 unsigned int status;
 unsigned int MaximalReceiveDataLength;
 unsigned char * ReceiveDataBuffer;
 unsigned int httpResponseValue;
 unsigned int receivedDataSize;

 // todo: check if internet is available 

 printf("START \n");
 
 // how much received data do we maximally want ? (this example: we want
 0 up to 128 chars)
 MaximalReceiveDataLength = 128;
 
 // get a buffer (on local heap) to store the received response
 ReceiveDataBuffer = (unsigned char *)malloc(MaximalReceiveDataLength);

 // did we got the memory ?
 if (ReceiveDataBuffer == 0)
 {
   printf(" out of memory ");
   return;
 }
 
 // go
 printf("calling http_get...\n");
 http_get(192,168,1,110, 80, "www.hostname.cz", "/index.htm", (void *)ReceiveDataBuffer, MaximalReceiveDataLength);
 
 // wait for the result
 status = http_get_status(&httpResponseValue, &receivedDataSize);
 while (status == 1023)
 {
   status = http_get_status(&httpResponseValue, &receivedDataSize);
 }
 
 // process the result
 if (status == 1024)
 {
    // all is great
    printf("DONE OK.  HTTP RESPSTAT = %u    receivedDataSize = %u\n", httpResponseValue, receivedDataSize);
    
    // now we can process the data (body text) of the server's response
    if (receivedDataSize > 0)
    {
      // for thix example, just simply print the text to console
      printf("%s", (char *)ReceiveDataBuffer);
    }
 } else
 {
    // status != 1024
    printf("FAILED. error code = %u \n", status);
 }
 
 // finally -> DO NOT FORGET to release the memory back to heap
 free(ReceiveDataBuffer); ReceiveDataBuffer = 0;
 
}

Příklad #2: HTTP GET

V tomto příkladu komunikuje SDS s webovým serverem na adrese 192.168.1.110 na TCP portu 80, a ignoruje datový obsah odpovědi serveru.

void main(void)
{
 unsigned int status;
 unsigned int httpResponseValue;

 // todo: check if internet is available 

 printf("START \n");
 
 // go
 printf("calling http_get...\n");
 http_get(192,168,1,110, 80, "www.hostname.cz", "/index.htm", (void *)0, 0);
 
 // wait for the result
 status = http_get_status(&httpResponseValue, 0);
 while (status == 1023)
 {
   status = http_get_status(&httpResponseValue, 0);
 }
 
 // process the result
 if (status == 1024)
 {
    // all great
    printf("DONE OK.  HTTP RESPSTAT = %u \n", httpResponseValue);

 } else
 {
    // status != 1024
    printf("FAILED. error code = %u \n", status);
 }
 
}


Příklad #3: HTTP POST

V tomto příkladu komunikuje SDS s webovým serverem na adrese 192.168.1.110 na TCP portu 80, a ignoruje datový obsah odpovědi serveru.

void main(void)
{
 unsigned int status;
 unsigned int httpResponseValue;

 // todo: check if internet is available 

 printf("START \n");
 
 // go
 printf("calling http_post...\n");
 http_post(192,168,1,110, 80, "www.hostname.cz", "/process.php", (void *)0, 0, "post text going to server");
 
 // wait for the result
 status = http_get_status(&httpResponseValue, 0);
 while (status == 1023)
 {
   status = http_get_status(&httpResponseValue, 0);
 }
 
 // process the result
 if (status == 1024)
 {
    // all great
    printf("DONE OK.  HTTP RESPSTAT = %u \n", httpResponseValue);

 } else
 {
    // status != 1024
    printf("FAILED. error code = %u \n", status);
 }
 
}


Nastavení uživatelského obsahu HTTP hlavičky

POZOR: toto je dostupné teprve ve firmware od 03/2023 !

Změna Content-Type

Ve výchozím stavu, vkládá SDS do HTTP-POST hlavičky (kterou SDS posílá na server), mimo jiné tento řádek:

Content-Type: text/plain

Obsah Content-Type je možné změnit pomocí funkce http_header_set_content_type().

Nastavená hodnota zůstává až do další změny touto funkcí. Na výchozí hodnotu (text/plain) je nastavena jedině vždy při startu nového (nebo restartu stejného) FC programu.

Zadejte čistě text parametru, příklad (bez uvozovek): "application/json" - tedy čistě to co je až za dvoutečkou, a bez ukončovacích znaků !

Tento příklad se realizuje takto:

 ret = http_header_set_content_type("application/json");

Pozor na maximální omezení délky tohoto textu (64 znaků).

Pozor - tato položka (Content-Type) je vložena jen do HTTP-POST hlavičky, kam správně patří (protože POST má i svůj datový obsah, který se z SDS odesílá, a jeho typ se právě takto popisuje).

Naopak hlavička HTTP-GET tento prvek neobsahuje (protože u GET se jedná čistě o dotaz). Pokud chcete určit, jaký obsahový typ má přijít v odpovědi na HTTP-GET dotaz, musíte použít tag "Accept: ...", který lze do hlavičky vložit následující funkcí.

Tedy ještě jednou - je to častá neznalost RFC pro HTTP komunikaci - pokud chcete určit jaký formát odpovědi má ze serveru přijít, dělá se to pomocí Accept (viz RFC9110), a nikoliv pomocí Content-Type !!!

Přidání dalšího uživatelského řádku do hlavičky

Pomocí funkce http_header_set_user_row() lze přidat jeden celý vlastní řádek. Tento řádek je přidán jak do HTTP-GET tak do HTTP-POST požadavků, odesílaných příslušnou FULL-C funkcí. Nastavená hodnota zůstává až do další změny touto funkcí (nebo až do nahrání nového FC programu, kde je při startu nového FC programu vždy tento nastavený obsah odstraněn).

Například:

X-THINGSPEAKAPIKEY: XXXXXXXXXXXXXXX

se do hlavičky přidá pomocí volání funkce:

 ret = http_header_set_user_row(0, "X-THINGSPEAKAPIKEY: XXXXXXXXXXXXXXX");

Tato funkce očekává celkový text plného řádku, ale pozor - bez ukončovacích znaků atd. - viz příklad výše.

Pozor na maximální délku textu, který lze do hlavičky vložit (128 znaků). V současném FW lze vložit jen jeden uživatelský řádek (lze si ale pomoct trikem, pokud se vám více řádků vleze do celkového délkového omezení, tak to snadno řešit lze).

Návratové hodnoty pro obě tyto funkce

Tyto dvě specifické funkce vracejí výsledek přímo v rámci své návratové hodnoty (na rozdíl od ostatních, které průběžné předávají hodnotu přes http_get_status() funkci).

Návratové hodnoty:

 0 = změna provedena
-1 = chybné parametry, neprovedeno
-2 = nelze změnit, protože HTTP-GET nebo HTTP-POST právě probíhá 
-4 = jiná chyba, neprovedeno


http_close()

Tuto funkci obvykle vůbec není potřeba použít.

Použití je jen ve speciálních případech, kdy už nechcete dále čekat na dokončení komunikace se http serverem.

Nelze totiž začít další http_get/post, dokud plně neskončil právě eventuálně probíhající.

V běžném provozu není tato funkce potřeba, neboť server ukončuje spojení ihned po přenesení odpovědi do SDS. Nicméně, pokud máte server který je nakonfigurován že vždy spojení neuzavře (forced persistent connection), pak je tato funkce řešením tohoto problému (váš program, po obdržení celé odpovědi, zavolá tuto funkci a tím slušně ukončí tcp spojení na server).


Stavové hodnoty / chyby

Program musí použít volání funkce http_get_status() pro zjištění okamžitého stavu. Tuto funkci lze použít pro GET i POST.

 http_get_status()          význam
-------------------------+-----------------------------------------------------------------------
 0                       |  klid, žádná akce nebyla zahájena
 1023                    |  právě probíhá požadovaná činnost, čekejte
 1024                    |  úspěsně provedeno (HTTP GET dotaz odeslán na server, a byla obdržena odpověď)
 1025                    |  nelze se připojit k serveru (činnost neprovedena)
 1026                    |  timeout (nepovedlo se provést činnost v určeném čase, limit je 45 vteřin)
 1027                    |  server předčasně ukončil spojení (nemáme odpověď, dotaz se zřejmě také nepovedlo předat)
 1028                    |  byly přijaty neplatné data v odpovědi ze serveru (neznáme odpověď)
 1029                    |  pokoušíte se poslat další dotaz, zatímco ten předchozí ještě nebyl dokončen (takže ten nový je ignorován a není proveden)
 1030                    |  zařízení SDS nemá platnou IP adresu (připojení k serveru neprovedeno, činnost neprovedena)
 1031                    |  zařízení SDS nemá funkční Ethernet (vytáhnutý kabel, vypnutý switch) (cinnost neprovedena)
 1032                    |  funkce byla zavolána s neplatnými parametry (činnost neprovedena)
 1033                    |  timeout
 1034                    |  nedostatek paměti (heap) pro provedení funkce