Table of Contents Previous Chapter




Att skriva Spinner-ulpcskript

I dokumentet nedan utgår jag ifrån att 
du har grundläggande kunskaper i 
uLPCprogrammering.

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

Definitionen 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.ulpc i ditt hemdir med innehåll enligt ovan, och sedan accessar http://www.lysator.liu.se/~ditt_namn/test.ulpc, så kommer du att få se 'Hello world' i din Netscape.

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

request_id - objektet med all info

TABELL 1. Kortfattad beskrivning av de flesta variablerna i request_id-objektet

---------------------------------------------------------------------------------------------------------------
Variabel                   Förklaring                                                                            
---------------------------------------------------------------------------------------------------------------
int time;                  När gjordes uppkopplingen? Sekunder sedan                                             
                           00:00:00 den 1/1 1970.                                                                
object conf;               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                    I HTTP finns det en kul sak som heter 'variabler', de kommer oftast från en           
(string:string) variab     'form'.                                                                               
les;                       I den här mappingen finns allihop instoppade, färdigparsade.                          
                           Exempel.                                                                              
                           En förfrågan efter filen /goo/bar?hmm=hej&foo=%20 kommer att resul                    
                           tera att variables sätts till ([ "hmm":"hej", "foo":" "]).                            
mapping (string:array      Blandat smått och gott. Du behöver nog inte bry dig, men man kan ju alltid            
(string)) misc;            skriva ut fältet för att se vad det innehåller:                                       
                           return sprintf("%O", request_id->misc);                                               
                           Här kan du även definiera dina egna variabler, om du mot all förmodan behöver         
                           det. Du bör dock se till att dina variabler har unika namn, om du inte vill råka ut   
                           för otrevliga överraskningar.                                                         
                           Variablerna är request-lokala.                                                        
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:                                        
                            ·  Den syns inte i URL-en                                                            
                            ·  Användaren kommer att ha kvar sin config även om hon avslutar sin Netscape        
                           och startar den igen.                                                                 
                            ·  Om folk lägger upp länkar till dina sidor i sina sidor kommer de inte att inklu   
                           dera konfigurationen.                                                                 
                           Men även några nackdelar:                                                             
                            ·  Det kan bara finnas en lista med konfigurerade val per server.                    
                            ·  Det är svårt att bli av med sin konfiguration.                                    
                            ·  Bara Netscape implementerar dem än.                                               
                           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.       
                           Man kan också använda SPML för att göra det <aconf +/-CONFIG></                       
                           aconf>.                                                                               
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ämpligtvis för att generera olika 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 pragmaheadrar 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 generera 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)                                 
                            ·   ({ 1, "username" }) (authentifiering skickad, och auth modulen                   
                           tycker att den är korrekt)                                                            
mapping                    Alla cookies som klienten har skickat.                                                
(string:string) cookies;                                                                                         
---------------------------------------------------------------------------------------------------------------

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

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. I annat fall så måste man 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.

TABELL 2. Hjälpfunktioner definierade i filen lpc/http.lpc, som ärvs av spinnerlib.

----------------------------------------------------------------------------------------------------------
Funktion                          Förklaring                                                                
----------------------------------------------------------------------------------------------------------
mapping                           Returnera en sträng som resultat, typen är text/html om inget annat       
http_string_answer(string         anges. Strängen kommer inte att parsas av spinner innan den returneras    
data, string|void type);          till klienten.                                                            
mapping                           Returnera en fil som resultat, typen är text/html om inget annat anges.   
http_file_answer(object fp,       Om man inte anger längden kommer spinner att ta reda på den själv. fp     
string|void type, void|int len);  ska vara en instans av /precompiled/file                                  
mapping http_redirect( string     En redirect till den url som anges. Om man skickar med request_id, och    
url, object|void request_id )     dessutom anger en relativ URL kommer både prestate och state att          
                                  adderas till URLen.                                                       
mapping                           Begär lösenord (authentifiering) inom namnrymden 'realm' på denna         
http_auth_failed(string realm)    server. Netscape sparar undan ett användarnamn och lösenord för varje     
                                  realm på varje server i minnet.                                           
mapping                           Samma sak som auth_failed, nästan, men man kan skicka med ett fel         
http_auth_required(string         meddelande som visas om användaren väljer 'nej tack', och en liten        
realm, string message)            annan kod används. Namnet säger nog det mesta -- required - Använda       
                                  ren har inte försökt logga in innan, och failed -- användaren misslycka   
                                  des. Ingen WWW-läsare som jag har sett skiljer på de här två              
                                  resultatkodena.                                                           
mapping                           Returnera ett meddelande med error_code som felkod. Se HTTP               
http_low_answer(int               specifikationen för en lista med dylika, eller /usr/www/spinner/          
error_code, string message)       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");                                               
                                                                                                            
----------------------------------------------------------------------------------------------------------

TABELL 3.

------------------------------------------------
tag          förklaring                           
------------------------------------------------
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         mimetypen som det som du             
             skickar tillbaka har. Om du inte     
             definierar 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 klien    
             ten. 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 kli    
             enten av spinner, och du förvän      
             tas hantera all socket               
             kommunikation och upprens            
             ning själv. Används av proxy         
             modulerna.                           
extra_heads  Dessa huvudfält kommer att           
             adderas till svaret. Ett använd      
             bart 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 definierade i /usr/      
             www/spinner/server/                  
             include/variables.h                  
             (den mest feldöpta filen i hela      
             Spinner..)                           
------------------------------------------------

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,

])

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

int no_reload(object request_id) { if(!request_id -> variables -> reload) return 1; return 0; }

Dvs om man returnerar ett så laddas skriptet inte om. Ovanstående exempel tillåter bara att man laddar om det om man har med formsvariabeln reload=<nånting, precis vad som helst> när man trycker på reload.


Garbs olämpliga läge

Det är lite olyckligt att Garbs utgivning sammanfaller med väldigt intressanta saker som händer med WWW-servern Spinner/Roxen. Det olyckliga ligger i att det infaller så dumt att Garb inte hinner rapportera om det intressanta som inträffar den 9:e september men ändå påverkar det korrektheten i artiklarna i och med att vissa namn är ändrade.

Jag hoppas och tror att artiklarna trots allt är intressanta.

Table of Contents Next Chapter