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.
|