Att skriva Spinner µLPC skript

Att skriva Spinner µLPC skript


I dokumentet nedan utgår jag ifrån att du har grundläggande kunskaper i µLPC programmering

Ett Spinner µLPC-skript är en liten programsnutt (egentligen ett µLPC objekt) som körs när användaren tittar på sidan, dvs, istället för att returnera skriptet returneras det som skriptet returnerar.

Defenitionen av ett skript är mycket enkel.

Nedan följer ett som implementerar ett gammalt känt testfall:

string|mapping parse(object request_id)
{
  return "Hello world!\n";
}

Om du skapar filen public_spinner/test.lpc i ditt hemdir med innehåll enligt ovan, och sedan accessar http://www.lysator.liu.se/~ditt_namn/test.lpc, så kommer du att få se 'Hello world' i din Netscape.

Men hur gör man för att föra lite mer intressanta saker, var finns information om forms-variables, prestate och liknande? Jo, i objektet request_id.

request_id - objektet med all info

Nedan följer en mycket kortfattad beskrivning av de flesta variablerna i objektet i fråga:

int time;
När gjordes uppkopplingen? Sekunder sedan 00:00:00 den 1/1 1970.

object conf;
Current configuration, en pekare till den virtuella server som requesten kom till (alltså den server som din modul ligger i).

Du behöver nog inte den här variabeln, om du inte vill utföra udda operationer.

string raw_url;
URLen helt oparsad som den kom från klienten.

mapping (string:string) variables;
I HTTP finns det en kul sak som heter 'variabler', de kommer oftast från en 'form'.

I den här mappingen finns allihop instoppade, färdigparsade.

Exempelvis:

En förfrågan efter filen /goo/bar?hmm=hej&foo=%20%20 kommer att resultera att variables sätts till ([ "hmm":"hej", "foo":" "]).

mapping (string:array (string)) misc;
Blandat smått och gott.. Du behöver nog inte bry dig, men man kan ju alltid skriva ut fältet för att se vad det innehåller: return sprintf("%O", request_id->misc);

list (string) prestate;
Prestate används mycket, iallafall på Lysator.

Det är en lista med strängar, man kan alltså göra saker som

if(request_id->prestate->nobg)
  no_background = 1;

Prestate skrivs innan filnamet I URLen, så här: /(foo,bar)/goo/bar

list (string) config;

Config fungerar precis som prestate, men det lagras inte undan i URLen, utan i client-side cookies. Detta har flera fördelar:

Men även några nackdelar:

För att addera något till 'config' låter man användaren accessa en fil enligt:

http://din.server:port/<+config,-config,...>/riktig/URL

Användaren kommer då att få configen tillagd till cookien Spinner-Config i sin klient, och få en redirect till /riktig/URL. Detta är mycket Spinner specifikt..

list (string) supports;
Vad klienten kan hantera.

Innehållet i den här listan kommer från filen etc/supports, per default. Det hela kan ändras i konfigurationsinterfacet.

Används lämpligtis för att konditionellt generera kod till olika klienter

Exempel:

  if(request_id->supports->tables)
     return make_table();
  else
     return make_pre();

string remoteaddr;
IP-nummret till datorn på andra sidan förbindelsen, som en sträng ("158.126.90.157")

array (string) client;
Vilken klient som frågar efter sidan, en array eftersom protokollet (HTTP/1.*) dumt nog tillåter flera User-Agent: header rader, och man vet ju aldrig..

Lämpligtvis använder man '*' operatorn för att få en sträng av det hela (request_id->client*""). Ofta är det dock mycket smartare att använda supports istället för client.

array (string) referer;
Den (eller de..) sidor som refererade till den här sidan.

list (string) pragma;
Alla pragma headrar klienten har skickat. Intressant är 'no-cache', som skickas när man trycker på 'reload' av de flesta klienter.

string prot;
Det protokoll som användes för att generara frågan, troligtvis HTTP/1.0 eller HTTP/1.1, men även saker som FTP, GOPHER och HTTP/0.9 kan förekomma.

string method;
Metod, troligtvis 'GET'.

string rest_query;
Allt efter ett '?' i URL-en som inte är variabler.

string raw;
Hela requesten som rå data.

string query;
Allt efter '?' i URLen.

string not_query;
Allt innan '?' i URLen exklusive prestate, det är det här som används av spinner för att få fram vilka moduler som requesten ska mappas genom.

string data;
Allt i en BODY i requesten. Oftast inte mycket, men vid metoden POST används det till alla variabler.

array (int|string) auth;
Antingen 0 (ingen authentifiering skickad av klienten),

({ 0, "username:password" }) (authentifiering skickad, men auth modulen tycker inte att den är korrekt, och användaren finns inte ens),

({ 0, "username" }) (authentifiering skickad, men auth modulen tycker inte att den är korrekt, och användaren finns)

eller

({ 1, "username" }) (authentifiering skickad, och auth modulen tycker att den är korrekt)

mapping (string:string) cookies;
Alla cookies som klienten har skickat.


Fast det räcker ju inte riktigt att ha tillgång till all data, man måste kunna returnera data också. Det gör man enligt nedan:

Att returnera data

Det enklaste fallet är att man helt enkelt returnerar en sträng. Den strängen kommer sedan att skickas genom Spinners parser, precis som vanliga HTML filer. Det kan vara mycket smidigt att returnera vanlig SPML kod från sina lpc skript.

Man kan annars returnera en mapping.

Att själv sätta ihop en mapping av det slag som ska returneras kan vara lite knivigt. Därför finns det en hel del hjälpfunktioner.

Alla är defenierade i filen lpc/http.lpc, som ärvs av spinnerlib, som man i sin tur lämpligen ärver i sina skript om man tänker använda de här funktionerna.

mapping http_string_answer(string data, string|void type);
Returnera en sträng som resultat, typen är text/html om inget annat anges. Strängen kommer inte att parsas av spinner innan den returneras till klienten.

mapping http_file_answer(object fp, string|void type, void|int len);
Returnera en fil som resultat, typen är text/html om inget annat anges. Om man inte anger längden kommer spinner att ta reda på den själv. fp ska vara en instans av /precompiled/file, eller ett objekt som implementerar samma metoder (du vill inte, jag lovar..)

mapping http_redirect( string url, object|void request_id )
En redirect till den url som anges. Om man skickar med request_id, och dessutom anger en relativ URL kommer prestate att adderas till URLen helt automatiskt.

mapping http_auth_failed(string realm)
Begär lösenord (authentifiering) inom namnrymden 'realm' på denna server. Netscape sparar undan ett användarnamn och lösenord för varje realm på varje server i minnet.

mapping http_auth_required(string realm, string message)
Samma sak som auth_failed, nästan, men man kan skicka med ett felmeddelande som visas om användaren väljer 'nej tack', och en liten annan kod används. Namnet säger nog det mesta -- required - Användaren har inte försökt logga in innan, och failed -- användaren misslyckades. Ingen WWW-läsare som jag har sett skiljer på de här två resultatkodena.

mapping http_low_answer(int error_code, string message)
Returnera ett meddelande med 'error_code' som felkod. Se HTTP specifikationen för en lista med dylika, eller /usr/www/spinner/server/include/variables.h

Kan användas så här:

if(search(lower_case(request_id->client*""), "aol") != -1)
  return http_low_answer(402, 
		"Please enter your VISA number and expiration date below:\n");

Om du hör till de som tycker att det är kul att pilla med detaljerna så är det här hur returmappingen egentligen ser ut: (alla fält kan utelämnas, men om man utelämnar alla samtidigt blir det inte mycket till svar.)

([
  "file":file_object,
  "data":"string",
  "len":int,
  "type":"main/sub",
  "raw":0|1,  
  "leave_me":0|1,
  "extra_heads":([ "name":"value, ... ]),
  "error":int,
])

file
Ett filobjekt som ska skickas till klienten. Skickas efter eventuell "data".

data
En sträng som ska skickas innan "file".

len
Längden av data och file ihop. Om du inte specifierar det här kommer den att räknas ut av Spinner.

type
mime typen som det som du skickar tillbaka har. Om du inte defenierar en kommer "text/plain" att användas.
raw
Om du sätter den här variabeln kommer _inget_ förutom det som du skriver att skickas till klienten. Du måste alltså generera alla headrar och liknande själv.

leave_me
Om du sätter den här variablen kommer inget att skickas till klienten av Spinner, och du förväntas hantera all socketkommunikation och upprensning själv. Används av proxy modulerna.

extra_heads
Dessa huvudfält kommer att adderas till svaret. Ett användbart värde är ([ "Expire":http_date(time()), ]) Nu kommer skriptets returvärde att expira direkt.

error
HTTP svarskoden som ska användas. 200 är normalt, alla koder finns defenierade i spinner/server/include/variables.h (den mest feldöpta filen i hela Spinner, skulle jag tro.)


Nu finns det bara några få saker till att känna till om skripten: