Interneto technologijos. Laboratorija: CGI. CGI programavimas asamblėjos kalba?!? - Lengvai! URL struktūra ir užklausų duomenų kodavimas
Straipsnis jau gana seniai cirkuliuoja internete, bet kaip autorius manau, kad turiu teisę jį čia patalpinti. Daug (jei ne viskas) čia parašyta yra pasenusi ir iš pirmo žvilgsnio gali pasirodyti nenaudinga, bet nuėjus šiuo keliu, po 6 metų galiu pasakyti, kad tai nebuvo nereikalinga. Taigi.
Šiame straipsnyje noriu pakalbėti apie CGI sąsają apskritai, jos įgyvendinimą langams ir ypač asamblėjos kalbos naudojimą rašant CGI programas. Į šio straipsnio taikymo sritį neįeina Pilnas aprašymas CGI, nes internete šiuo klausimu yra tiesiog jūra medžiagos ir aš tiesiog nematau prasmės visa tai čia perpasakoti.
CGI teorija
CGI – (bendra šliuzo sąsaja)- Bendroji šliuzo sąsaja. Kaip jau galima spėti, ši sąsaja tarnauja kaip vartai tarp serverio (čia turiu omenyje programą – serverį) ir kažkokios išorinės programos, parašytos OS, kurioje veikia šis serveris. Taigi, CGI yra atsakinga už tai, kaip duomenys bus perkelti iš serverio programos į CGI programą ir atvirkščiai. Sąsaja nenustato jokių apribojimų, ant ko turi būti rašoma CGI programa, tai gali būti įprastas vykdomasis failas arba bet koks kitas failas – svarbiausia, kad serveris galėtų jį paleisti (pvz., „Windows“ aplinkoje tai gali būti failas su plėtiniu, pridėtas prie bet kurios programos).Nuo to momento, kai paskambinote (pavyzdžiui, paspaudėte formos, prie kurios pridedamas CGI programos iškvietimas) mygtuką, CGI programą, kol naršyklės lange gausite rezultatą, vyksta:
- Žiniatinklio klientas (pavyzdžiui, naršyklė) sukuria ryšį su URL nurodytu serveriu;
- Žiniatinklio klientas siunčia užklausą serveriui, ši užklausa dažniausiai atliekama dviem būdais GET arba POST;
- Duomenis iš kliento užklausos (pavyzdžiui, formos laukų reikšmes) serveris per CGI sąsają perduoda į URL nurodytą CGI programą;
- CGI programa apdoroja iš serverio gautus kliento duomenis ir, remdamasi šiuo apdorojimu, sukuria atsakymą klientui, kurį per tą pačią CGI sąsają siunčia serveriui, o šis, savo ruožtu, perduoda tiesiogiai klientui. ;
- Serveris nutraukia ryšį su klientu.
Standartinėje CGI specifikacijoje daroma prielaida, kad serveris gali susisiekti su programa toliau nurodytais būdais:
- Aplinkos kintamieji – juos gali nustatyti serveris paleisdamas programą;
- Standartinis įvesties srautas (STDIN) – jo pagalba serveris gali perduoti duomenis į programą;
- Standartinis išvesties srautas (STDOUT) – programa gali įrašyti į jį savo išvestį, kuri perduodama į serverį;
- Komandų eilutė - joje serveris gali perduoti programai kai kuriuos parametrus.
Standartiniai įvesties / išvesties srautai yra labai patogūs ir plačiai naudojami UNIX sistemose, ko negalima pasakyti apie „Windows“, todėl yra CGI specifikacija, sukurta specialiai „Windows“ sistemoms, vadinamoji „Windows CGI“. Bet, žinoma, standartiniai įvesties / išvesties srautai taip pat gali būti naudojami Windows CGI programavimui. Čia neliesiu „Windows CGI“ standarto ir tam yra bent dvi priežastys – pirmoji ir svarbiausia – šiuo metu ne visi „Windows“ http serveriai palaiko šią specifikaciją (ypač mano mėgstamiausia Apache 1.3.19)... Antrąją priežastį galite pastebėti įvesdami bet kurią paieškos variklis eilutė „Windows CGI“. Norėčiau atkreipti dėmesį tik į bendrą šios sąsajos informaciją - visi duomenys iš serverio į klientą perduodami per įprastą * .ini failą, skirtą langams, kurio pavadinimas perduodamas programai komandinėje eilutėje. Tokiu atveju visus failo duomenis serveris jau kruopščiai suskirsto į skyrius ir tereikia naudoti „GetPrivateProfile*“ funkciją, kad juos iš ten ištrauktumėte. Atsakymas vėl siunčiamas į serverį per failą, kurio pavadinimas nurodomas atitinkamame ini-failo įraše.
Kokius duomenis klientas gali perkelti į CGI programą? - beveik bet koks. Paprastai programa gauna kliento užpildomų formos laukų reikšmes, tačiau tai gali būti ir bet kokie dvejetainiai duomenys, pavyzdžiui, failas su paveikslėliu ar muzika. Duomenis į serverį gali perkelti dviese skirtingi metodai Yra GET metodas ir POST metodas. Kurdami užpildyti formą savo puslapyje, aiškiai nurodome, kuriuo iš pateiktų metodų norime siųsti vartotojo įvestus duomenis, tai daroma pagrindinėje formos žymoje taip:
Siunčiant duomenis GET metodu, naršyklė nuskaito duomenis iš formos ir deda po scenarijaus URL, po klaustuko, jei formoje yra keli reikšmingi laukai, jie visi perduodami per „&“ ženklą, lauko pavadinimas ir jo reikšmė įrašomi URL per „ = “. Pavyzdžiui, užklausa, kurią naršyklė sugeneruoja iš formos paspaudus mygtuką, prie kurio pridedamas scenarijus „/cgi-bin/test.exe“, atsižvelgiant į tai, kad pirmasis formos laukas vadinamas „jūsų_vardas“, antrasis - "jūsų_amžius" gali atrodyti taip:
GAUTI /cgi-bin/test.exe?your_name=Pupkin&your_age=90 HTTP / 1.0
Naudojant GET metodą yra keletas trūkumai– visų pirma – t. duomenys perduodami URL, tada tų pačių perduodamų duomenų kiekis yra ribojamas. Antrasis trūkumas vėlgi kyla dėl URL - tai yra konfidencialumas, tokiu būdu perduodant duomenis, duomenys lieka visiškai atviri. Taigi, gerai, jei formoje turime 2-3 mažus laukus... kyla klausimas, ką daryti, jei yra daugiau duomenų? Atsakymas yra naudoti POST metodą!
Naudojant POST metodą, duomenys į serverį perduodami kaip duomenų blokas, o ne URL, o tai šiek tiek atlaisvina rankas, kad padidėtų perduodamos informacijos kiekis, pavyzdžiui, aukščiau pateiktame POST formos pavyzdyje, blokas siunčiamas į serveris bus maždaug toks:
POST /cgi-bin/test.exe HTTP / 1.0
Priimti: tekstas / paprastas
Priimti: tekstas / html
Priimti: * / *
Turinio tipas: programa / x-www-form-urlencoded
Turinio ilgis: 36
tavo_vardas = šuniukas ir tavo_amžius = 90
Kaip minėta aukščiau, serveris, gavęs duomenis, turi juos transformuoti ir perduoti CGI programai. Standartinėje CGI specifikacijoje duomenis, kuriuos klientas įvedė GET užklausoje, serveris įdeda į programos aplinkos kintamąjį „QUERY_STRING“. Kai pateikiama POST užklausa, duomenys patalpinami į standartinį programos įvesties srautą, iš kurio juos galima nuskaityti. Be to, su tokia užklausa serveris nustato dar du aplinkos kintamuosius – CONTENT_LENGTH ir CONTENT_TYPE, pagal kuriuos galima spręsti apie užklausos ilgį baitais ir jos turinį.
Be pačių duomenų, serveris nustato kitus iškviestos programos aplinkos kintamuosius, pateiksiu kai kuriuos iš jų:
REQUEST_METHOD
Nurodo, kokiu būdu buvo gauti duomenys
Pavyzdys: REQUEST_METHOD = GAUTI
QUERY_STRING
Pateikite užklausos eilutę, jei buvo naudojamas GET metodas
Pavyzdys: QUERY_STRING = jūsų_vardas = šuniukas ir jūsų_amžius = 90 ir hobis = asm
CONTENT_LENGTH
Užklausos teksto ilgis baitais
Pavyzdys: CONTENT_LENGTH = 31
TURINIO TIPAS
Prašyti kūno tipo
GATEWAY_INTERFACE
CGI protokolo versija
Pavyzdys: GATEWAY_INTERFACE = CGI / 1.1
REMOTE_ADDR
Nuotolinio pagrindinio kompiuterio, tai yra kliento, kuris paspaudė mygtuką formoje, IP adresas
Pavyzdys: REMOTE_ADDR = 10.21.23.10
REMOTE_HOST
Nuotolinio pagrindinio kompiuterio pavadinimas, tai gali būti jo domeno pavadinimas arba, pavyzdžiui, kompiuterio pavadinimas Windows aplinka, jei jų negalima gauti, lauke nurodomas jo IP
Pavyzdys: REMOTE_HOST = wasm.ru
SCRIPT_NAME
Užklausoje naudoto scenarijaus pavadinimas.
Pavyzdys: SCRIPT_NAME = / cgi-bin / gols.pl
SCRIPT_FILENAME
Scenarijaus failo pavadinimas serveryje.
Pavyzdys: SCRIPT_FILENAME = c: /page/cgi-bin/gols.pl
SERVER_SOFTWARE
Serverio programinė įranga
Pavyzdys: Apache / 1.3.19 (WIN32)
Iškviesta CGI programa gali nuskaityti bet kuriuos serverio nustatytus aplinkos kintamuosius ir panaudoti juos savo naudai.
Apskritai, tai yra trumpai viskas, daugiau informacijos apie „General Gateway“ sąsają rasite specializuotoje dokumentacijoje, šį aprašymą sudariau norėdamas jums priminti, o jei nežinojote, tada atnaujinti. Pabandykime ką nors padaryti praktiškai.
Praktinė dalis
Praktikai reikia bent 3 dalykų - kažkokio http serverio Windows, visus pavyzdžius išbandžiau ant Apache 1.3.19 for Windows, serveris nemokamas, galite parsisiųsti iš iTaip, ir mums reikia ne serverio, o serverio, sukonfigūruoto paleisti cgi scenarijus! Žr. dokumentaciją, kaip tai daroma jūsų naudojamame serveryje. Antras dalykas, kurio mums reikia, žinoma, yra surinkėjas, taip pat būtina, kad kompiliatorius palaikytų konsolinių WIN32 programų kūrimą, aš naudoju Tasm, bet Fasm ir Masm ir daugelis kitų * asms puikiai tiks. Ir galiausiai, svarbiausia, kad šis noras yra reikalingas.
Taigi, manau, kad jūs sėkmingai įdiegėte ir sukonfigūravote serverį, kad serverio dokumentų šakniniame kataloge būtų failas index.html, kuris puikiai rodomas naršyklėje, kai įvedate adresą 127.0.0.1. Taip pat atsižvelgsiu į tai, kad kažkur serverių aplankų džiunglėse yra „cgi-bin“ aplankas, kuriame leidžiama paleisti scenarijus.
Patikrinkime serverio sąranką ir tuo pačiu parašykime nedidelį scenarijų. Mūsų scenarijus bus įprastas * .bat failas. Numatau klausimus – kaip? tikrai? Taip, tai yra įprastas paketinis failas, kaip minėta aukščiau, CGI specifikacija neskiria failų tipų, svarbiausia, kad serveris galėtų jį paleisti, o jis, savo ruožtu, turi prieigą prie stdin / stdout ir aplinkos kintamųjų, bat failą, kad ir ne iki galo, bet pavyzdžiui jis mums puikiai tiks. Sukurkime failą su kažkuo tokiu:
@echo išjungtas
rem Užklausos antraštė
echo Turinio tipas: tekstas / html
aidas.
rem Prašymo įstaiga
aidas „Sveiki!
echo "Gauti užklausą gauti duomenys:% QUERY_STRING%
Pavadinkime failą test.bat ir patalpinkime jį į skriptų paleidimo katalogą, greičiausiai tai bus „cgi-bin“ katalogas. Kitas dalykas, kurį turime padaryti, yra kažkaip pavadinti šį scenarijų, iš esmės tai galima padaryti tiesiogiai naršyklės adreso lange įvedus kažką panašaus į šį "http://127.0.0.1/cgi-bin/test.bat" , bet vadinkim iš mūsų pagrindinio puslapio, tuo pačiu patikrinsime GET metodo veikimą. Serverio šaknyje sukurkime failą index.html su tokiu turiniu:
Dabar įėjus į serverį (naršyklės adreso juostoje http://127.0.0.1) turėtų pasirodyti forma, į ją ką nors įvesti ir paspausti mygtuką "siųsti", jei viskas buvo padaryta teisingai, pamatysite atsakymą mūsų šikšnosparnis. Dabar pažiūrėkime, ką mes ten sujaukėme.
Kaip jau galima spėti, komanda „echo“ išveda į stdout, pirmiausia perduodame savo atsakymo antraštę serveriui – „echo Content-type: text / html“. Tai standartinė CGI specifikacijos antraštė, kuri sako, kad norime perkelti tekstinį ar html dokumentą, yra ir kitų antraščių. Labai svarbus momentas – antraštė turi būti atskirta nuo atsakymo teksto tuščia eilute, ką darome su kita „echo“ komanda. Toliau perduodamas pats atsakymo turinys - tai paprastas html dokumentas, dokumento turinyje, kad būtų aiškumo, pavaizduoju vieną iš aplinkos kintamųjų, kuriuos mums perdavė serveris - "QUERY_STRING", kaip jau minėta su GET metodas (ir tai yra mūsų atvejis) šiame kintamajame visi vartotojo įvesti duomenys, kuriuos galime stebėti scenarijaus atsakyme. Galbūt pastebėjote "ne vietoje kabutes" paskutinėse 2 failo eilutėse, iškart po "echo", jos yra dėl bat failų specifikos, nes matote, kad html žymos yra įrėmintos simboliais "<» и «>", Tuo pačiu metu šie simboliai tarnauja kaip įvesties / išvesties peradresavimas bat failuose, todėl negalime jų laisvai naudoti čia.
Rekomenduoju šiek tiek pažaisti su panašiais bat-skriptais, tai gali būti labai naudinga, pabandykite pažvelgti į kitus aplinkos kintamuosius. Pasakysiu šiek tiek, nukrypdamas nuo temos, UNIX sistemose apvalkalo kalbos yra labai išvystytos ir riba tarp programavimo apvalkalo kalba ir programavimo „tikra“ programavimo kalba kai kuriais atvejais yra labai neaiški, todėl , UNIX sistemose gana dažnai paprasti scenarijai rašomi būtent komandų interpretatorių kalbomis, tačiau Windows interpreter cmd.exe arba, anksčiau, command.com, šiems tikslams yra akivaizdžiai silpni.
Dabar pereikime prie svarbiausios šio straipsnio užduoties – iš tikrųjų parašyti CGI programą asambliuke. Iš esmės, jei atsižvelgsime į visa tai, kas išdėstyta pirmiau apie CGI, galime padaryti išvadą, ko CGI sąsaja reikalauja iš mūsų programos:
- Programa turi turėti galimybę nuskaityti standartinį įvesties srautą (stdin), kad galėtų pasiekti POST metodu pateiktus duomenis;
- Programa turi sugebėti rašyti į standartinį išvesties srautą (stdout), kad savo darbo rezultatą perduotų į serverį;
- Iš pirmųjų dviejų punktų išplaukia, kad tam, kad serveris galėtų ką nors išsiųsti į mūsų programą stdin, o ji galėtų atsakyti į tai stdout, CGI programa turi būti konsolės programa;
- Mūsų programa turi sugebėti nuskaityti savo aplinkos kintamuosius.
Pradėkime nuo paskutinio punkto. Norint pasiekti „Windows“ programos aplinkos kintamuosius, naudojama API funkcija „GetEnvironmentStrings“, funkcija neturi argumentų ir grąžina žymeklį į aplinkos kintamųjų masyvą (NAME = VALUE), atskirtą nuliu, masyvas uždaromas dvigubu simboliu. nulis, kai programa paleidžiama serverio į programos aplinką, be standartinių kintamųjų pridedami aukščiau aprašyti specifiniai CGI kintamieji, paleisdami programą iš komandinės eilutės, jų, žinoma, nematysite.
Norėdami ką nors parašyti į stdout arba nuskaityti iš stdin, pirmiausia turime gauti šių srautų rankenas, tai daroma naudojant API funkciją "GetStdHandle", funkcijai kaip parametras perduodama viena iš šių reikšmių:
- STD_INPUT_HANDLE - stdin (standartinė įvestis);
- STD_OUTPUT_HANDLE - stdout (standartinė išvestis);
- STD_ERROR_HANDLE – skirta stderr.
Funkcija grąžins rankenėlę, kurios mums reikia skaitymo / rašymo operacijoms. Kitas dalykas, kurį turime padaryti, yra rašyti / skaityti šiuos srautus. Tai atliekama įprastomis failų skaitymo/rašymo operacijomis, t.y. ReadFile ir WriteFile. Čia yra vienas subtilumas, galite manyti, kad šiems tikslams galite naudoti WriteConsole / ReadConsole, bet tai tikrai tinka konsolei ir veiks gerai, rezultatai, kaip ir naudojant WriteFile, bus išvesti į konsolę, bet tai tęsis tol, kol paleisime savo programą kaip scenarijų serveryje. Taip nutinka todėl, kad serveriui paleidus mūsų programą, funkcijos „GetStdHandle“ grąžintos rankenos nebebus konsolės rankenos, o bus vamzdžių rankenos, reikalingos ryšiui tarp dviejų programų.
Štai trumpas pavyzdys, kaip turėtų atrodyti CGI surinkimo programa:
386
.model flat, stdcall
includelib import32.lib
.konst
PAGE_READWRITE = 4 val
MEM_COMMIT = 1000 val
MEM_RESERVE = 2000 val
STD_INPUT_HANDLE = -10
STD_OUTPUT_HANDLE = -11
Duomenys
hStdout dd?
hStdin dd?
hMem dd?
antraštė:
db "Turinio tipas: tekstas / html", 13,10,13,10,0
start_html:
db" CGI programos aplinka atrodo taip:
",13,10,0
for_stdin:
db" Programos STDIN yra:
",13,10,0
end_html:
Db "", 13.10.0
parašyta dd?
toscr db 10 dup (32)
db "- Failo tipas", 0
.kodas
_start:
Xarba ebx, ebx
skambinkite GetStdHandle, STD_OUTPUT_HANDLE
mov hStdout, eax
skambinkite GetStdHandle, STD_INPUT_HANDLE
mov hStdin, eax
Iškvieskite write_stdout, poslinkio antraštę
skambinkite write_stdout, offset start_html
Skambinti VirtualAlloc, ebx, 1000, MEM_COMMIT + MEM_RESERVE, PAGE_READWRITE
mov hMem, eax
mov edi, eax
skambinkite GetEnvironmentStringsA
mov esi, eax
next_ymbol:
mov al,
arba al, al
jz end_string
mov, al
next_string:
cmpsb
jmp trumpas next_ymbol
end_string:
mov, "> rb<"
pridėti red., 3
cmp baitas ptr, 0
jnz next_string
inc red
stosb
skambinkite write_stdout, hMem
skambinkite write_stdout, offset for_stdin
Skambinkite GetFileSize ,, ebx
mov edi, hMem
iškviesti ReadFile ,, edi, eax, offset nwritten, ebx
pridėti edi,
mov baitas ptr, 0
skambinkite write_stdout, hMem
skambinkite write_stdout, offset end_html
skambinkite „VirtualFree“, „hMem“.
skambinkite ExitProcess, -1
Write_stdout proc bfOffs: dword
skambinkite lstrlen, bfOffs
skambinti WriteFile ,, bfOffs, eax, offset nwritten, 0
ret
write_stdout endp
extrn GetEnvironmentStringsA: šalia
extrn GetStdHandle: šalia
extrn ReadFile: šalia
extrn WriteFile: šalia
extrn GetFileSize: šalia
extrn VirtualAlloc: šalia
extrn VirtualFree: šalia
extrn ExitProcess: šalia
extrn lstrlen: šalia
baigiasi
pabaiga _pradžia
Vykdomasis failas yra sukurtas naudojant šias komandas:
tasm32.exe / ml test.asm
tlink32.exe / Tpe / ap / o test.obj
Nepamirškite, kad programa turi būti konsolės pagrindu.
Šią programą galite iškviesti naudodami aukščiau aprašytą html formą, tereikia pakeisti pavadinimą test.bat formoje į test.exe ir nukopijuoti jį atitinkamai į / cgi-bin / ir galite jį nustatyti POST užklausos metodas, programa jį apdoroja.
Taip pat noriu atkreipti dėmesį, kad galite iškviesti programą kitaip, galite sukurti failą cgi-bin kataloge, pavyzdžiui, test.cgi su viena eilute "#! C: / _ path_ / test.exe" ir iškvieskite jį užklausose, o serveris savo ruožtu nuskaitys pirmąją eilutę ir paleis exe failą, tam būtina, kad * .cgi plėtinys kaip scenarijų plėtinys būtų užregistruotas http serverio nustatymuose. Taikant šį metodą, serveris paleis mūsų programą su komandine eilute „test.exe path_to_test.exe“, tai turi keletą privalumų – pirmas yra tas, kad žmogus, vykdantis mūsų scenarijų, net nenumanys, ant ko scenarijus parašytas, antrasis. - kadangi, pavyzdžiui, su mūsų eilute mums perduodamas failo pavadinimas, prie šio failo galime pridėti bet kokius savo scenarijaus nustatymus, o tai supaprastina derinimą, beje, taip veikia visi interpretatoriai - jūs jau pastebėjote, kad visose perl / php / etc programose yra panaši eilutė - nurodant patį apvalkalą. Taigi, kai serveris paleidžia cgi programą, jei programos plėtinys nustatymuose įrašytas kaip scenarijus, jis nuskaito pirmąją failo eilutę, o jei pasirodo, kad ji yra aukščiau aprašyto formato, tada paleidžiama programa, nurodyta eilutėje su šio failo pavadinimu, įskaitant tarpą, tarkime, kad eilutėje nurodomas perlų interpretatorius, gavęs tokią dovaną, jis pradeda vykdyti, nes komentaras perle yra simbolis "#", tada jis praleidžia pirmąją eilutę ir tęsiasi tolimesnis scenarijaus vykdymas, apskritai dalykas yra patogus.