IPRO - PC Magazine Romania, Iunie 2003
SOLUȚII PENTRU PROGRAMATORII ȘI DESIGNERII WEB Librăria
libcurl
Konstantin Klyagin
Fiecare programator profesionist știe ce înseamnă un deadline (dată de predare).
Înaintea unui deadline, când nu mai ai timp să scrii ceva, ideal este să
găsești o soluție deja creată de un alt programator, și care să se potrivească
proiectului tău. În special dacă acea soluție salvatoare constă într-un cod
sursă scris de altcineva și care se poate folosi pentru a realiza o mare
parte din funcționalitățile care mai trebuiau implementate. Astăzi vă voi
prezenta un astfel de caz din propria experiență. Veți afla cum lumea Open
Source îi poate ajuta pe programatorii care lucrează la dezvoltarea de programe
comerciale.
Mai precis, este vorba despre realizarea unui client de HTTP într-un program
scris în limbajul de programare C++ pentru Windows. Acel program este dezvoltat
de firma la care lucrez, și, la fel ca restul produselor noastre, este
dedicat procesării unor imagini.
Bineînțeles, când se plănuia facilitatea de trimitere a fișierelor grafice
către server, fără îndoială a fost ales protocolul HTTP ca fiind cel
mai standardizat, sigur și flexibil dintre cele existente.
Dar degeaba mă așteptam să găsesc o asemenea funcție în bibliotecile
standard ale lui Visual C++. Este drept că el are clasa HttpClient
care poate servi
cereri simple (simple request), poate face și metoda POST, dar pentru
a trimite fișiere este nevoie de mai mult și în particular, de suport
pentru
conținut
"multipart" și codare "mime". Din păcate, ultimele două lucruri lipseau
punând un semn de întrebare asupra planului nostru luând în considerare
și deadline-urile.
Imediat am pornit o căutare pe google încercand să găsesc ceva deja
scris. Câteva minute mai târziu eram la http://
curl.haxx.se/ și
descărcam sursele.
Chiar dacă numele curl nu sună prea bine în românește, ceea ce am
văzut după aceea m-a uimit.
Pachetul conține un utilitar și o bibliotecă, utilitarul constând
într-o interfață gen linie de comandă pentru utilizarea bibliotecii,
în care
doar cu ajutorul câtorva funcții simple se poate face aproape orice
cu protocoalele
internet HTTP, HTTPS, FTP, Gopher, TELNET și DICT. Printre capacitățile
suportate se numără primirea și transmiterea unor documente cu
posibilitatea de a continua
de la poziția unde a fost întrerupt ultimul transfer, suport pentru
server-e proxy și autentificarea cu "login" și "password". Se poate
folosi în
programele multithread și în afară de toate astea, sursele se compilează
în Linux,
BSD, SunOS, MacOS X, Windows, OpenVMS, IRIX, Tru64, HP-UX, pe toate
arhitecturile pe care acestea merg.
Dar haideți să vedem cum se rezolvă problema de mai sus, folosind
biblioteca de funcții libcurl.
CURL *curl;
CURLcode res;
struct HttpPost *formpost, *lastptr;
formpost = lastptr = NULL;
curl_formadd(&formpost, &lastptr,
CURLFORM_COPYNAME, "username",
CURLFORM_COPYCONTENTS, "pamela", CURLFORM_END);
curl_formadd(&formpost, &lastptr,
CURLFORM_COPYNAME, "password",
CURLFORM_COPYCONTENTS, "secret", CURLFORM_END);
curl_formadd(&formpost, &lastptr,
CURLFORM_COPYNAME, "file",
CURLFORM_FILE, "myphoto.jpg", CURLFORM_END);
curl = curl_easy_init();
if(curl) {
curl_easy_setopt(curl, CURLOPT_URL, "http://www.playboy.com/");
curl_easy_setopt(curl, CURLOPT_HTTPPOST, formpost);
res = curl_easy_perform(curl);
curl_easy_cleanup(curl);
curl_formfree(formpost);
}
După cum se vede din cod, setarea majorității parametrilor inițiali se face
înainte ca cererea (request-ul) să fie executat, cu ajutorul unor apeluri
către curl_easy_setopt(), fiecare apel schimbând câte o setare. De exemplu,
pentru a citi pagina returnată de server-ul web, se poate atașa o funcție
callback:
curl_easy_setopt(curl,
CURLOPT_CURLOPT_WRITEFUNCTION, &wfunc);
Write function aici se referă la nevoia bibliotecii de a scrie undeva datele
pe care le primește de la server, iar funcția
writefunc are următorul prototip:
size_t wfunc(void *ptr, size_t size, size_t nmemb, void *stream);
Funcția va fi apelată pentru fiecare pachet de date primit. Exemplul de
mai jos ilustrează cum se poate face descărcarea unui fișier de pe un server
FTP.
#include <curl/curl.h>
FILE *f;
int ftpwrite(void *buffer, size_t size, size_t nmemb, void *stream) {
if(!f) {
f = fopen("curl.tgz", "wb");
if(!f) return -1;
}
return fwrite(buffer, size, nmemb, f);
}
int main() {
CURL *curl;
CURLcode res;
f = NULL;
curl = curl_easy_init();
if(curl) {
curl_easy_setopt(curl, CURLOPT_URL,
"ftp://ftp.sunet.se/pub/www/utilities/curl/curl-7.10.4.tar.gz");
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, ftpwrite);
curl_easy_setopt(curl, CURLOPT_VERBOSE, TRUE);
res = curl_easy_perform(curl);
curl_easy_cleanup(curl);
}
if(f)
fclose(f);
return 0;
}
Setarea opțiunii CURL_VERBOSE vă va da posibilitatea de a vedea cu ce se
ocupă la un moment dat biblioteca, pe durata apelului curl_easy_perform().
Vreți ca o cerere (request) să meargă printr-un server proxy? Poftim, se
face prin adăugarea unei singure linii:
curl_easy_setopt(curl,
CURLOPT_PROXY, "http://proxy.my.net:8080/");
Pentru mai multe informații legate de opțiunile blibliotecii libcurl uitați-vă
la pagina man a funcției curl_easy_setopt(). Aveți la dispoziție 80 de parametri
diferiți ce pot fi setați astfel încât să satisfacă orice dorințe, inclusiv
pe cele exotice. Bineînțeles, referitoare doar la executarea unor operațiuni
cu protocoalele internet.
Din exemplele date mai sus vedem că orice protocol dintre cele suportate
de curl se poate folosi la fel de ușor, diferența între abordări fiind
aproape inexistentă. Acest fapt îmi inspiră asociarea cu standardul URL unificat,
care permite specificarea locației oricărui document în următorul mod bine
cunoscut:
<protocol>://<nume>:<parola>@<server>:<port>/<locatie>
La fel și libcurl-ul oferă o interfață universală pentru accesarea documentelor.
Prin aceasta putem constata că nu este doar o bibliotecă de funcții, ci o
întreagă tehnologie bine gândită, cu ajutorul căreia orice protocol se
poate utiliza la fel de ușor.
Biblioteca de funcții libcurl nu este dedicată exclusiv programatorilor în
C ci oferă și altora posibilitatea de a scrie repede și ușor programe client.
Popularitatea bibliotecii i-a inspirat și pe cei care utilizează alte limbaje.
Ei au creat interfețe pentru PHP, Perl, Pascal, Basic, Cocoa, Dylan, Euphoria,
Java, Lua, Object-Pascal, OCaml, Postgres, Python, Rexx, Ruby, Scheme si
Tcl. Spre exemplu, iată cum arată cel mai simplu script PHP care folosește
libcurl.
<?php
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, "http://konst.org.ua/");
curl_setopt($ch, CURLOPT_HEADER, 0);
curl_exec($ch);
curl_close($ch);
?>
Acum a venit momentul să vă țineți mai bine de scaune, căci se vor spune
câteva cuvinte despre licența sub care se distribuie această bibliotecă minunată.
Fiind un efort comun al multor oameni care au contribuit la dezvoltarea lui,
libcurl este făcut cu scopul ca foarte mulți dezvoltatori să profite de el,
indiferent de genul software-ului pe care îl produc. Fiindcă produsele noastre
ca și cele dezvoltate de majoritatea firmelor de software pentru Windows
sunt comerciale, mă temeam că nu-l voi putea folosi datorită licenței care
ar fi putut să nu permită utilizarea bibliotecii la programe de acest gen.
Dar ceea ce am găsit în FAQ m-a bucurat foarte mult. Veți afla imediat de
ce.
Conform punctului "License issues" din FAQ, această bibliotecă poate fi
folosită la orice fel de proiecte, atât în programe distribuite sub licență
"free",
printre care se numără GPL, LGPL, BSD cât și în cele comerciale, în cazul
cărora codul sursă nu este disponibil. Acest fel de reguli de distribuire
se numește "Mozilla Public License". Singura restricție pe care o pune
un astfel de licență este interdicția de a modifica textele în sursele care
stabilesc drepturile de copiere. Adică nu puteți schimba numele autorului
cu altceva, ceea de, de altfel nici nu este necesar.
Ce să vă mai spun? Acest produs chiar este făcut de programatori pentru
pentru programatori. Este evident că un asemenea instrument n-are cum
să aibă succes
comercial, el nefiind dedicat utilizatorului final, însă în același timp
îi poate ajuta pe mulți programatori. Până la urmă, faptul că cineva
a folosit o biblioteca distribuită gratuit pentru-un produs comercial nu
înseamnă neapărat
că persoana respectivă n-a contribuit la mișcarea Open Source undeva
în altă parte. Foarte mulți dezvoltatori de software, care crează programare
comerciale
la servici, în timpul liber contribuie semnificativ la mișcarea GNU și
Open Source.
Exemplul librăriei de funcții libcurl dovedește că cele două feluri de
dezvoltare a aplicațiilor, cel comercial și cel "Open Source", nu se
exclud unul pe
celălalt, ci se completează perfect.
Dezvoltarea aplicațiilor "Open Source" prezintă avantaje atât pentru
programatorii de rând care pot folosi munca altor programatori cât
și pentru firme care
pot să se concentreze pe dezvoltarea de programe specializate, fără
să mai piardă timpul cu rezolvarea unor probleme comune de programare,
sau..
chiar
mai mult, să trebuiască să cumpere acele soluții.
|