Content Rewriting

Back

Introduzione

LBL ADC implementa il content rewriting in modalità nativa e come componente fondamentale nel governo dei servizi applicativi. Il sistema è stato studiato sia per un utilizzo di rewriting in senso stretto, rewriting di HTTP HEADER o HTTP BODY, sia come sistema di integrazione layer 7 e layer 4.

Da disegno progettuale è stata data la possibilità di utilizzare regole descrittive fino ad utilizzare il linguaggio di programmazione JAVA o linguaggi di scripting. Queste due modalità di rewriting possono essere utilizzate contemporaneamente.

Altro aspetto fondamentale di cui si è tenuto conto durante la progettazione è la facilità di utilizzo ed una “leggibilità intuitiva” nel tempo di quanto sviluppato sia nelle regole descrittive sia a livello di programmazione.

Questo documento tratta l’argomento rewriting utilizzando tantissimi esempi in modo da poter essere poi riutilizzati nei propri progetti.

Rewriting

Con l’argomento rewriting si identificano i processi che, filtrando i dati in transito attraverso un gateway, possono modificare i contenuti.

In un processo di trasformazione di questo tipo risulta evidente che la pertinenza delle modifiche apportate deve essere molto rigorosa andando quest’ultima ad incidere non solo nei contenuti ma anche a livello di protocollo e quindi influenzando i comportamenti.

Il sistema di rewriting dovrà quindi fornire gli strumenti necessari per modificare i contenuti in maniera selettiva con semplicità.

Intervenire sul protocollo richiede ovviamente una certa consapevolezza delle modifiche che si vogliono apportare andando ad incidere sull’erogazione del servizio. Ciò nondimeno il sistema dovrà essere sufficientemente astratto da nascondere la complessità delle tecnologie assicurando all’utilizzatore il risultato finale.

Vista l’articolazione dell’argomento un altro aspetto da tenere in considerazione è la possibilità di intervenire attraverso semplici regole descrittive lasciando la possibilità di intervenire anche attraverso estensioni di classi JAVA o di scripting con un vero e proprio linguaggio di programmazione.

Quest’ultimo aspetto, oltre al rewriting, permette di svolgere attività di integrazione con gli applicativi andando a gestire attività come il Single Sign On (SSO) oppure aspetti di attribuzione dell’utilizzo delle applicazioni per successiva fatturazione o suddivisione per centri di costo.

HTTP Rewriting

LBL ADC implementa il rewriting del protocollo http attraverso lo sviluppo di regole descrittive.

Le regole vengono etichettate con un nome in modo da poterle riutilizzare su diversi flussi informativi e a diversi livelli favorendo lo sviluppo di proprie librerie di regole.

In LBL ADC con il protocollo http, possono essere descritte due tipi di regole, una relativa all’HEADER e l’altra relativa al BODY. Questi due elementi infatti contraddistinguono il messaggio http. Entrambe queste regole vengono implementate in maniera simile per diversificarsi solo per gli scopi di pertinenza.

Le regole che andremo a sviluppare andranno ad agire nell’HEADER e nel BODY attraverso due paragrafi racchiusi dal paragrafo <rewriteManagement> all’interno del file iproxy.xml:

<rewriteManagement>

<rewriteHeaderRule>

</rewriteHeaderRule>

...

...

<rewriteBodyRule>

</rewriteBodyRule>

...

...

</rewriteManagement>

 

 

Ogni regola verrà identificata da un proprio nome univoco in modo da poter essere utilizzata nei vari servizi descritti nel paragrafo <virtualDomain> e per differenza fino ai paragrafi <endp>.

<rewriteManagement>

<rewriteHeaderRule name=”fromHttpsToHttp302”>

</rewriteHeaderRule>

<rewriteHeaderRule name=”fromHttpsToHttp301”>

</rewriteHeaderRule>

...

...

<rewriteBodyRule name=”changeColor”>

</rewriteBodyRule>

<rewriteBodyRule name=”tcoprojectDevToRelative”>

</rewriteBodyRule>

...

...

</rewriteManagement>

 

 

In questo caso abbiamo creato 4 regole, due relative alle HEADER e due relative ai BODY.

Per utilizzare queste regole, attualmente vuote, sarà sufficiente dichiarale sui servizi in cui si vogliono applicare:

<endpoints>

<endPointsGrouping enable="true">

<virtualDomain virtualDomainName="www.tcoproject.dev" enable="true"

rewriteHeaderRules="fromHttpsToHttp301 fromHttpsToHttp302"

rewriteBodyRules="traduci tcoprojectDevToRelative tcoprojectDevToRelativePOST ilAAItToRelative ilBBbolItToRelative CCItToRelativeAll adserver.ilDD.it Reload_frame LBL">

<endp address="legendonebackend" port="8181" uriPath="/papaia" enable="true"/>

<endp address="legendonebackend" port="8181" uriPath="/prvSevletEcho" enable="true"/>

<endp address="legendonebackend" port="8181" uriPath="/training" enable="true"/>

<endp address="legendonebackend" port="8181" uriPath="/trainingw" enable="true"/>

<endp address="legendonebackend" port="8282" uriPath="/papaia" enable="true"/>

<endp address="legendonebackend" port="8282" uriPath="/prvServletEcho" enable="true"/>

<endp address="legendonebackend" port="8282" uriPath="/training" enable="true"/>

<endp address="legendonebackend" port="8282" uriPath="/trainingw" enable="true"/>

<endp address="legendtwobackend" port="8181" uriPath="/papaia" enable="true"/>

<endp address="legendtwobackend" port="8181" uriPath="/prvServletEcho" enable="true"/>

<endp address="legendtwobackend" port="8181" uriPath="/training" enable="true"/>

<endp address="legendtwobackend" port="8181" uriPath="/trainingw" enable="true"/>

<endp address="legendtwobackend" port="8282" uriPath="/papaia" enable="true"/>

<endp address="legendtwobackend" port="8282" uriPath="/prvServletEcho" enable="true"/>

<endp address="legendtwobackend" port="8282" uriPath="/training" enable="true"/>

<endp address="legendtwobackend" port="8282" uriPath="/trainingw" enable="true"/>

<endp address="legendonebackend" port="8585" uriPath="/TCOProject" enable="true"/>

<endp address="legendonebackend" port="8585" uriPath="/TCOProjectSrv" enable="true"/>

<endp address="legendonebackend" port="8585" uriPath="/CEC2003" enable="true"/>

<endp address="legendonebackend" port="8585" uriPath="/publictest" enable="true"/>

<endp address="legendtwobackend" port="8585" uriPath="/TCOProject" enable="true"/>

<endp address="legendtwobackend" port="8585" uriPath="/TCOProjectSrv" enable="true"/>

<endp address="legendtwobackend" port="8585" uriPath="/CEC2003" enable="true"/>

<endp address="legendtwobackend" port="8585" uriPath="/publictest" enable="true"/>

<endp address="legendonebackend" port="8787" uriPath="/TCOProject" enable="true"/>

<endp address="legendonebackend" port="8787" uriPath="/TCOProjectSrv" enable="true"/>

<endp address="legendtwobackend" port="8787" uriPath="/TCOProject" enable="true"/>

<endp address="legendtwobackend" port="8787" uriPath="/TCOProjectSrv" enable="true"/>

<endp address="legendonebackend" port="8585" uriPath="/Flowers/album" enable="true"/>

<endp address="legendtwobackend" port="8585" uriPath="/Flowers/album" enable="true"/>

<endp address="legendonebackend" port="8787" uriPath="/Flowers/album" enable="true"/>

<endp address="legendtwobackend" port="8787" uriPath="/Flowers/album" enable="true"/>

<endp address="legendonebackend" port="8383" uriPath="" enable="false"/>

<endp address="legendtwobackend" port="8383" uriPath="" enable="false"/>

<endp address="legendonebackend" port="54443" SSL="true" uriPath=""

rewriteHeaderRules="test000 test001" rewriteBodyRules="changeColor" enable="true"/>

<endp address="legendtwobackend" port="54443" SSL="true" uriPath=""

rewriteHeaderRules="test000 test001" rewriteBodyRules="changeColor" enable="true"/>

<endp address="legendonebackend" port="8484" uriPath="/SurfaceCluster"

associateName="SCDEGroup_00000" loadBalancingType="FailOver" enable="true"/>

<endp address="legendtwobackend" port="8484" uriPath="/SurfaceCluster"

associateName="SCDEGroup_00001" loadBalancingType="FailOver"

healthCheck="false" enable="true"/>

</virtualDomain>

</endPointsGrouping>

...

...

 

Queste regole, ora vuote, verranno implementate successivamente.

HTTP HEADER Rewriting

Per HTTP HEADER Rewriting si intendono tutte le possibilità di modifica dei contenuti dell’HEADER oppure ad un cambiamento di comportamento, ad esempio un redirect.

Prenderemo come primo esempio il passaggio da una trasmissione HTTPS ad una trasmissione HTTP. Le modifiche all’HEADER saranno relative alle richieste di redirect dei servizi che dovranno essere trasformate da HTTPS (del servizio) ad HTTP. Prendiamo questo processo ad esempio in quanto il processo inverso, da HTTPS a HTTP (terminatore SSL), viene effettuato automaticamente da LBL ADC in maniera trasparente.

L’esempio di seguito effettuerà questo tipo di cambiamento solo nei casi in cui è richiesto.

Riprendendo il nostro esempio XML dovremo andare a descrivere in quali flussi vogliamo eseguire il cambiamento. Volendo eseguire il cambiamento nel flusso di ritorno dal server, il response, andremo ad indicare nelle regole che la loro applicazione dovrà avvenire solo in quel senso.

<rewriteManagement>

<rewriteHeaderRule flow="RESPONSE" name=”fromHttpsToHttp302”>

</rewriteHeaderRule>

<rewriteHeaderRule flow="RESPONSE" name=”fromHttpsToHttp301”>

</rewriteHeaderRule>

...

...

<rewriteBodyRule name=”changeColor”>

</rewriteBodyRule>

<rewriteBodyRule name=”tcoprojectDevToRelative”>

</rewriteBodyRule>

...

...

</rewriteManagement>

 

Con il parametro “flow” siamo andati ad identificare il verso di applicazione della regola. Il parametro “flow” può avere tre valori: RESPONSE, REQUEST, BOTH, in dipendenza del flusso che vogliamo intercettare.

In questa immagine viene evidenziala la differenziazione del flusso di REQUEST e di RESPONSE:

Dopo aver identificato il flusso che vogliamo intercettare dobbiamo sempre più “filtrare” la regola solamente per gli eventi che tipizzeranno la sua applicazione. Come vedremo in seguito LBL ADC, nei paragrafi di rewriting (<rewriteHeaderRule> e <rewriteBodyRule>), implementa un sistema finissimo di Conditions. Per facilitare le implementazioni sono state comunque messe a disposizione alcune tra le condizioni più utilizzate direttamente sul paragrafo <rewriteHeaderRule> (ed in egual misura nel paragrafo <rewriteBodyRule>).

Tra queste condizioni ad esempio è possibile indicare direttamente il parametro responseCode per il quale applicare la regola. Se valorizzato responseCode verrà preso in considerazione solamente nel flusso di resposne.

<rewriteManagement>

<rewriteHeaderRule flow="RESPONSE" name=”fromHttpsToHttp302”

responseCode="302">

</rewriteHeaderRule>

<rewriteHeaderRule flow="RESPONSE" name=”fromHttpsToHttp301”

responseCode="301">

</rewriteHeaderRule>

...

...

<rewriteBodyRule name=”changeColor”>

</rewriteBodyRule>

<rewriteBodyRule name=”tcoprojectDevToRelative”>

</rewriteBodyRule>

...

...

</rewriteManagement>

 

 

In questo caso le due regole identificate dai nomi “fromHttpsToHttp302” e “fromHttpsToHttp301” verranno applicate solo in corrispondenza del flusso di RESPONSE e solo nei casi di ridirezione comandati dai servizi di backend identificati dai codici di ritorno 302, MOVED TEMPORARILY, e 301 MOVED PERMANENTLY.

Di seguito, dopo aver identificato esattamente il flusso e la condizione di applicazione, andremo a delimitare ulteriormente il confine d’azione delle regole limitandole ad un solo dominio.

<rewriteManagement>

<rewriteHeaderRule flow="RESPONSE" name=”fromHttpsToHttp302”

responseCode="302">

<conditions>

<cond from="ENTITY" name="Location">

<regexTag>^https://www.tcoproject.dev</regexTag>

</cond>

<cond from="INNERVAR"

name="REQUEST_HTTP_HOST_NAME">

<regexTag>www.tcoproject.dev</regexTag>

</cond>

</conditions>

</rewriteHeaderRule>

<rewriteHeaderRule flow="RESPONSE" name=”fromHttpsToHttp301”

responseCode="301">

<conditions>

<cond from="ENTITY" name="Location">

<regexTag>^https://www.tcoproject.dev</regexTag>

</cond>

<cond from="INNERVAR"

name="REQUEST_HTTP_HOST_NAME">

<regexTag>www.tcoproject.dev</regexTag>

</cond>

</conditions>

</rewriteHeaderRule>

...

...

<rewriteBodyRule name=”changeColor”>

</rewriteBodyRule>

<rewriteBodyRule name=”tcoprojectDevToRelative”>

</rewriteBodyRule>

...

...

</rewriteManagement>

 

 

Risultato dell’introduzione di questo nuovo paragrafo <conditions> è l’applicazione della regola solo per le HEADER che cercano di effettuare un redirect su URL con protocollo https al dominio www.tcoproject.dev.

In questo esempio è stato introdotto quindi il concetto di “condizione” esplicita in un paragrafo. La condizione può essere esercitata su tutti gli elementi dell’HEADER o su parti di essi attraverso espressioni regolari.

Di seguito saranno analizzate punto per punto le condizioni sopra esposte. La costruzione di una condizione comincia dal paragrafo <conditions>. Questo paragrafo contiene tutte le condizioni relative alla regola. Tutte le condizioni saranno valutate con un operatore AND (default) se non diversamente specificato dall’apposito parametro “operator”:

<conditions operator="AND">

<cond ...

<cond ...

...

<conditions operator="OR">

<cond ...

<cond ...

...

 

Nel nostro caso non avendo indicato un operator verrà automaticamente assunto l’operatore AND e quindi solo se tutte le condizioni all’interno del paragrafo <conditions> saranno verificate la regola verrà applicata. La prima condizione, identificata dal paragrafo <cond>, indica prima di tutto da dove si vuole ricavare l’elemento da verificare.

<conditions>

<cond from="ENTITY" name="Location">

<regexTag>^https://www.tcoproject.dev</regexTag>

</cond>

...

 

Nel parametro “from” possono essere indicati i seguenti elementi da cui trarre le informazioni:

INNERVAR=Valori precaricati da LBL ADC per facilitare le operazioni

INNER VARIABLES

===============

REQUEST_HTTP_URL=Request URL with params and query string

REQUEST_HTTP_URL_LAST_ELEMENT=only last element of the URL without params and

query string

REQUEST_HTTP_URI_PATH=Only URI Path whithout parameters and query string

REQUEST_HTTP_HOST_NAME=hosname in entity “Host” (ATTENZIONE: L’utilizzo di questa

innervar può determinare la risoluzione del nome attraverso DNS.

Se il nome non è associato a nessun indirizzo il suo timeout può

causare un forte rallentamento)

REQUEST_HTTP_HOST_PORT=port number in entity “Host”

REQUEST_HTTP_COOKIES_LIST=list of cookies names separated by “;”

REQUEST_CLIENT_ADDRESS=TCP client address

RESPONSE_ENDPOINT_ADDRESS=TCP endpoint address

SSL_CONNECTION_CLIENT = true se il client si connette in SSL con LBL

SSL_CONNECTION_ENDPOINT = true se l’endpoint si connette in SSL con LBL

SSL_CONNECTION_REENCRYPTION = true se viene eseguita la reencryption SSL

(quindi LBL fa la terminazione SSL e si connette verso l’endpoint in SSL)

REQUEST_INCOMING_ADDRESS = indirizzo locale sul quale e’ stata accettata la richiesta

di servizio

REQUEST_INCOMING_HOST_NAME = nome host o indirizzo locale sul quale e’ stata accettata

la richiesta di servizio (ATTENZIONE: L’utilizzo di questa

innervar può determinare la risoluzione del nome attraverso DNS.

Se il nome non è associato a nessun indirizzo il suo timeout può

causare un forte rallentamento)

REQUEST_HTTP_SCHEME = http o https in base al tipo di connessione del client verso LBL

HIGH_WATER_YELLOW_WARNING_REACHED = se true è stata superata la soglia Yellow

Warning. Indica quindi un carico rilevante ma non ancora

critico.

HIGH_WATER= number of connection requests in the queue in long format.

HIGH_WATER_LEVEL= % Of connection requests in the queue compared to the number of

tunnels contemporary settings, this is a float value.

TUNNEL_SESSIONS_ACTIVE= Instant active tunnels, int format.

TUNNEL_SESSIONS_COMMITTED= Instant tunnel committed, (subset of TUNNEL_SESSIONS_ACTIVE”

Questi valori “precaricati” per essere utilizzati come modificatori (%xxx%) devono

comunque essere caricati in una variabile locale alla regola.

ENTITY=caricamento della variabile descritta in varName con il valore dell’Entity

dell’HEADER HTTP il cui nome è indicato in name.

URI_PARAM=caricamento della variabile descritta in varName con il valore del

parametro o query string dell’HEADER HTTP il cui nome è indicato in

name.

CONSTANT=caricamento della variabile descritta in varName con il valore del parametro

indicato in name. Solo in questo caso il valore contenuto in name può essere

composto da un’altra variabile precedentemente caricata.

COOKIE=caricamento della variabile descritta in varName con il valore del Cookie

dell’HEADER HTTP il cui nome è indicato in name.

VARIABLE=caricamento della variabile descritta in varName con il valore di un’altra variabile il cui nome è indicato in name.

Una completa trattazione di tutti gli argomenti e parametri è disponibile sul manuale LBL S.A.A.I. Reference Guide. In questo caso la prima condizione di verifica viene estratta da un ENTITY.

Per ENTITY si intende un elemento dell’HEADER HTTP delimitato da un CRLF.

GET / HTTP/1.1

Host: www.tcoproject.dev

User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.0; it; rv:1.9.2.2) Gecko/20100316 Firefox/3.6.2

Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8

Accept-Language: it-it,it;q=0.8,en-us;q=0.5,en;q=0.3

Accept-Encoding: gzip,deflate

Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7

Keep-Alive: 115

Connection: keep-alive

Cookie: LBLSESSIONID=1277228676044; TCOPROJECTAUTH=1277048578420; TCOPROJECTSESSIONID=1277048578511; SSID_caltagroup=453794224774; SV_caltagroup=1276415693024

HTTP/1.1 302 MOVED TEMPORARILY

Server: TCOProject(r)-http-appserver/3.1

Date: Sun, 164 Jun 2010 10:40:26 CEST

Content-Length: 0

Location: https://www.tcoproject.dev/login.html

In questo caso per ENTITY si intendono

Host,

User-Agent,

Accept,

Location,

etc…

Mentre il loro valore è rispettivamente:

www.oplon.net

Mozilla/5.0 (Windows; U; Windows NT 6.0; it; rv:1.9.2.3) Gecko/20100401…

image/png,image/*;q=0.8,*/*;q=0.5

https://www.tcoproject.dev/login.html

Quindi, con l’espressione di seguito, si estrae il valore dall’ENTITY “Location” e si verifica, attraverso una espressione regolare, che il contenuto abbia valore “https://www.tcoproject.dev” con partenza dal primo carattere (indicato con l’espressione “^”).

<cond from="ENTITY" name="Location">

<regexTag>^https://www.tcoproject.dev</regexTag>

</cond>

 

Se il valore contenuto riportasse: “hTtPs://wWw.TcOpRoJeCt.DeV” comunque il risultato sarebbe verificato in quanto le condizioni non sono caseSensitve. Se volessimo indicare una espressione regolare con distinzione tra caratteri minuscoli e maiuscoli potremmo indicarlo nel paragrafo <conditions> al parametro caseSensitve che per default viene valorizzato a false:

In questo caso tutte le condizioni non saranno caseSensitive se non diversamente indicato sui singoli paragrafi <conf>:

<conditions caseSensitive=”false”>

<cond from="ENTITY" name="Location">

<regexTag>^https://www.tcoproject.dev</regexTag>

</cond>

...

 

In questo caso tutte le condizioni non saranno caseSensitive mentre la prima condizione terrà conto della differenza di caratteri:

<conditions caseSensitive=”false”>

<cond from="ENTITY" name="Location" caseSensitive=”true”>

<regexTag>^https://www.tcoproject.dev</regexTag>

</cond>

...

 

In questo caso tutte le condizioni saranno caseSensitive se non diversamente indicato come nella prima condizione:

<conditions caseSensitive=”true”>

<cond from="ENTITY" name="Location" caseSensitive=”false”>

<regexTag>^https://www.tcoproject.dev</regexTag>

</cond>

...

 

 

Nel caso specifico dell’esempio essendo l’URISchema e l’URIHost non sensibili alla differenziazione minuscole o maiuscole (come da raccomandazioni W3C) il test più esatto da farsi è caseSensitive=”false”.

Andiamo ora ad analizzare la seconda condizione:

<conditions>

<cond from="ENTITY" name="Location">

<regexTag>^https://www.tcoproject.dev</regexTag>

</cond>

<cond from="INNERVAR"

name="REQUEST_HTTP_HOST_NAME">

<regexTag>www.tcoproject.dev</regexTag>

</cond>

</conditions>

 

Questa seconda condizione verifica che l’Host al quale era stata indirizzata la richiesta sia equivalente all’Host di ridirezione in risposta per poter eseguire il rewriting. Infatti, se fosse stato differente non si sarebbe dovuto eseguire il rewriting essendo un redirect non pertinente al dominio interessato. Con questa verifica si introduce una nuova sorgente di informazioni e cioè le INNERVAR. Per INNERVAR si indicano un insieme di valori già disponibili all’utilizzo per facilitare la scrittura delle regole di rewriting. In questo caso pur essendo in un flusso di RESPONSE possiamo verificare anche i valori della REQUEST che lo ha generato.

Altri tipi di sorgenti di informazione si possono utilizzare come sopra indicato nella lista.

Una volta inserite le condizioni di verifica si possono inserire le azioni che si vogliono intraprendere nell’HEADER.

Le azioni nell’HEADER possono essere di due tipi:

1- Modifiche a uno o più elementi dell’HEADER

2- Comandare un redirect

Per modificare uno o più elementi dell’HEADER è sufficiente inserire il paragrafo <entities> che sarà utilizzato per elencare le azioni da intraprendere.

<rewriteManagement>

<rewriteHeaderRule flow="RESPONSE" name=”fromHttpsToHttp302”

responseCode="302">

<conditions>

<cond from="ENTITY" name="Location">

<regexTag>^https://www.tcoproject.dev</regexTag>

</cond>

<cond from="INNERVAR"

name="REQUEST_HTTP_HOST_NAME">

<regexTag>www.tcoproject.dev</regexTag>

</cond>

</conditions>

<entities>

<entity entityName="Location" action="change">

<regexTag>^https</regexTag>

<replaceTo>http</replaceTo>

</entity>

</entities>

</rewriteHeaderRule>

<rewriteHeaderRule flow="RESPONSE" name=”fromHttpsToHttp301”

responseCode="301">

<conditions>

<cond from="ENTITY" name="Location">

<regexTag>^https://www.tcoproject.dev</regexTag>

</cond>

<cond from="INNERVAR"

name="REQUEST_HTTP_HOST_NAME">

<regexTag>www.tcoproject.dev</regexTag>

</cond>

</conditions>

<entities>

<entity entityName="Location" action="change">

<regexTag>^https</regexTag>

<replaceTo>http</replaceTo>

</entity>

</entities>

</rewriteHeaderRule>

 

Il paragrafo <entities> contiene le azioni da effettuarsi nell’HEADER.

<entities>

<entity entityName="Location" action="change">

<regexTag>^https</regexTag>

<replaceTo>http</replaceTo>

</entity>

</entities>

</rewriteHeaderRule>

 

Nel caso specifico si agirà nel valore dell’ENTITY “Location” cambiando (change), il valore che inizia con “https” con il valore corrispondente “http“:

…DA:

HTTP/1.1 302 MOVED TEMPORARILY

Server: TCOProject(r)-http-appserver/3.1

Date: Sun, 164 Jun 2010 10:40:26 CEST

Content-Length: 0

Location: https://www.tcoproject.dev/login.html

…A:

HTTP/1.1 302 MOVED TEMPORARILY

Server: TCOProject(r)-http-appserver/3.1

Date: Sun, 164 Jun 2010 10:40:26 CEST

Content-Length: 0

Location: http://www.tcoproject.dev/login.html

Questa semplice operazione permette di avere come risultato finale una trasmissione dati con sorgente HTTP e i servizi corrispondenti in HTTPS.

Come detto precedentemente LBL®ADC nel flusso inverso, cioè come terminatore di sessione HTTPS, esegue questa operazione automaticamente e quindi non è necessaria nessuna operazione.

HTTP HEADER Rewriting REDIRECT

Altra possibilità a livello di HEADER è eseguire un redirect condizionato. Ovviamente questo sarebbe possibile modificando ENTITY per ENTITY l’HEADER. Essendo un’operazione molto utilizzata si è creato un paragrafo apposito <redirectTo> per facilitare l’operazione.

<rewriteHeaderRule enable="true" flow="REQUEST" name="test000" caseSensitive="false"

httpInterceptorClass="loadbalancer.rewriter.LBLHTTPRewriteInterceptorHeaderLogging"

httpMethod="GET">

<conditions operator="AND">

<cond from="INNERVAR" name="REQUEST_HTTP_HOST_NAME">

<regexTag>www.tcoproject.dev</regexTag>

</cond>

<cond from="INNERVAR" name="REQUEST_HTTP_URL" caseSensitive="true">

<regexTag>^/viewProcessProperties.html\?process=A00_LBLGoSysCommand$</regexTag>

</cond>

<cond from="INNERVAR" name="REQUEST_HTTP_URI_PATH">

<regexTag>^/viewProcessProperties.html$</regexTag>

</cond>

<cond from="ENTITY" name="Connection">

<regexTag>Keep-alive</regexTag>

</cond>

<cond from="URI_PARAM" name="process">

<regexTag>A00_LBLGoSysCommand</regexTag>

</cond>

</conditions>

<redirectTo responseCode="302" redirectURL="http://www.tcoproject.dev/training?myParam=AAA"/>

</rewriteHeaderRule>

 

A questo punto si dovrebbe già essere in grado di “leggere” questa regola di rewriting anche se sono stati introdotti nuovi elementi come i parametri flow=”REQUEST” e httpMethod=”GET” che filtrano le richieste con metodo HTTP GET e che soddisfano anche altre condizioni prima di eseguire quanto stabilito sul paragrafo <redirectTo>.

Se tutte le condizioni vengono verificate allora verrà comandato un redirect con response code 302 all’indirizzo http://www.tcoproject.dev/training con una query string myParam=AAA.

Un nuovo parametro invece merita un approfondimento, il parametro è httpInterceptorClass valorizzato in questo caso con “loadbalancer.rewriter.LBLHTTPRewriteInterceptorHeaderLogging”.

Questo parametro indica alla regola di eseguire anche una classe utente. Questa funzionalità verrà approfondita in seguito.

HTTP HEADER Rewriting with VARIABLES

L’utilizzo delle variabili è quanto di più semplificativo e potente sia stato realizzato per estrarre dei valori dai dati in transito e comporre in maniera semplice nuovi valori da riutilizzare. Le variabili, come le condizioni, possono essere utilizzate sia nelle regole di rewriting dell’HEADER sia nelle regole di rewriting del BODY.

Per variabile si intende un “nome simbolico” che sta ad indicare un valore in un determinato contesto in un determinato momento.

Nelle regole di rewriting le variabili sono utilizzate per memorizzare dei valori che possono derivare da diverse fonti precedentemente dichiarate, ivi comprese delle variabili stesse.

Il caso che vogliamo utilizzare per spiegare l’utilizzo delle variabili è lo stesso del redirect precedente dove però l’URL di ridirezione verrà popolata da valori costanti e con valori variabili provenienti dal flusso dati stesso.

Immaginiamo di voler eseguire un redirect con un parametro avente come valore il valore ricavato da un COOKIE se valorizzato.

<rewriteHeaderRule enable="true" flow="REQUEST" name="test000" caseSensitive="false"

httpInterceptorClass="loadbalancer.rewriter.LBLHTTPRewriteInterceptorHeaderLogging"

httpMethod="GET">

<variables>

<var varName="MY_LBLSESSIONID" name="LBLSESSIONID" from="COOKIE"/>

</variables>

<conditions>

<cond from="COOKIE" name="LBLSESSIONID" eval="NOT">

<regexTag></regexTag>

</cond>

<cond from="INNERVAR" name="REQUEST_HTTP_HOST_NAME">

<regexTag>www.tcoproject.dev</regexTag>

</cond>

<cond from="INNERVAR" name="REQUEST_HTTP_URL" caseSensitive="true">

<regexTag>^/viewProcessProperties.html\?process=A00_LBLGoSysCommand$</regexTag>

</cond>

</conditions>

<redirectTo responseCode="302"

redirectURL="http://www.lblloadbalancer.dev/training?myParam=%MY_LBLSESSIONID%"/>

</rewriteHeaderRule>

 

Si nota immediatamente un nuovo paragrafo identificato dal tag <variables> e un nuovo parametro a livello di condizione: eval=”NOT”.

Nello specifico il paragrafo <variables> serve a dichiarare le variabili che verranno caricate durante il flusso dati. Anche in questo caso le fonti di caricamento delle variabili possono essere molteplici e per la maggior parte di queste fonti sono in comune con le fonti presenti sul paragrafo di condizione.

In questo caso il valore verrà caricato con il contenuto del COOKIE LBLSESSIONID solamente se presente.

<variables>

<var varName="MY_LBLSESSIONID" name="LBLSESSIONID" from="COOKIE"/>

</variables>

 

Altre sorgenti di informazioni possono essere utilizzate allo scopo di caricamento di una variabile e di seguito un elenco delle sorgenti di informazione. Per i dettagli, ed un elenco completo, si rimanda al manuale LBL®ADC Reference Guide:

INNERVAR=Valori precaricati da LBL ADC per facilitare le operazioni

INNER VARIABLES

===============

REQUEST_HTTP_URL=Request URL with params and query string

REQUEST_HTTP_URL_DECODED =Request URL with params and query string decoded

REQUEST_HTTP_URL_LAST_ELEMENT=only last element of the URL without params and

query string

REQUEST_HTTP_URI_PATH=Only URI Path whithout parameters and query string

REQUEST_HTTP_URI_PATH_DECODED=URI Path whithout parameters and query string in decoded format

REQUEST_HTTP_HOST_NAME=hosname in entity “Host” (ATTENZIONE: L’utilizzo di questa

innervar può determinare la risoluzione del nome attraverso DNS.

Se il nome non è associato a nessun indirizzo il suo timeout può

causare un forte rallentamento)

REQUEST_HTTP_HOST_PORT=port number in entity “Host”

REQUEST_HTTP_COOKIES_LIST=list of cookies names separated by “;”

REQUEST_CLIENT_ADDRESS=TCP client address

RESPONSE_ENDPOINT_ADDRESS=TCP endpoint address

SSL_CONNECTION_CLIENT = true se il client si connette in SSL con LBL

SSL_CONNECTION_ENDPOINT = true se l’endpoint si connette in SSL con LBL

SSL_CONNECTION_REENCRYPTION = true se viene eseguita la reencryption SSL

(quindi LBL fa la terminazione SSL e si connette verso l’endpoint in SSL)

REQUEST_INCOMING_ADDRESS = indirizzo locale sul quale e’ stata accettata la richiesta

di servizio

REQUEST_INCOMING_HOST_NAME = nome host o indirizzo locale sul quale e’ stata accettata

la richiesta di servizio (ATTENZIONE: L’utilizzo di questa

innervar può determinare la risoluzione del nome attraverso DNS.

Se il nome non è associato a nessun indirizzo il suo timeout può

causare un forte rallentamento)

REQUEST_HTTP_SCHEME = http o https in base al tipo di connessione del client verso LBL

HIGH_WATER_YELLOW_WARNING_REACHED = se true è stata superata la soglia Yellow

Warning. Indica quindi un carico rilevante ma non ncora

critico.

HIGH_WATER= number of connection requests in the queue in long format.

HIGH_WATER_LEVEL= % Of connection requests in the queue compared to the number of

tunnels contemporary settings, this is a float value.

TUNNEL_SESSIONS_ACTIVE= Instant active tunnels, int format.

TUNNEL_SESSIONS_COMMITTED= Instant tunnel committed, (subset of TUNNEL_SESSIONS_ACTIVE”

ACTUAL_TUNNEL_SESSIONS_SIZE= The actual size of tunnels: (usually equal to

“MAX_TUNNEL_SESSIONS_SIZE”)

MAX_TUNNEL_SESSIONS_SIZE= Maximum number of tunnels set.

Questi valori “precaricati” per essere utilizzati come modificatori (%xxx%) devono

comunque essere caricati in una variabile locale alla regola.

ENTITY=caricamento della variabile descritta in varName con il valore dell’Entity

dell’HEADER HTTP il cui nome è indicato in name.

URI_PARAM=caricamento della variabile descritta in varName con il valore del

parametro o query string dell’HEADER HTTP il cui nome è indicato in

name.

URI_PARAM_DECODED=Valore del parametro “name” preso dalla query string del HEADER HTTP, in formato decoded

CONSTANT=caricamento della variabile descritta in varName con il valore del parametro

indicato in name. Solo in questo caso il valore contenuto in name può essere

composto da un’altra variabile precedentemente caricata.

COOKIE=caricamento della variabile descritta in varName con il valore del Cookie

dell’HEADER HTTP il cui nome è indicato in name.

VARIABLE=caricamento della variabile descritta in varName con il valore di un’altra variabile il cui nome è indicato in name.

Altro elemento nuovo è la condizione che riporta il modificatore eval=”NOT”. Questa condizione negativizza il risultato che quindi se risulterà vuoto verrà scartato dando esito negativo:

<cond from="COOKIE" name="LBLSESSIONID" eval="NOT">

<regexTag></regexTag>

</cond>

 

Il paragrafo <redirectTo> riporta l’URL di ridirezione con parti costanti e parti variabili derivate dal passaggio di informazioni:

<redirectTo responseCode="302"

redirectURL="http://www.lblloadbalancer.dev/training?myParam=%MY_LBLSESSIONID%"/>

 

L’esempio di seguito riporta una regola con un utilizzo, didattico, intensivo delle variabili:

<rewriteHeaderRule enable="true" flow="REQUEST" name="test001" caseSensitive="false"

httpInterceptorClass="loadbalancer.rewriter.LBLHTTPRewriteInterceptorHeaderLogging"

httpMethod="GET">

<variables>

<!-- load variables from innervar -->

<var varName="MY_REQUEST_HTTP_URL" name="REQUEST_HTTP_URL" from="INNERVAR"/>

<var varName="MY_REQUEST_LAST_URL_ELEMENT" name="REQUEST_HTTP_URL_LAST_ELEMENT" from="INNERVAR"/>

<var varName="MY_REQUEST_HTTP_URI_PATH" name="REQUEST_HTTP_URI_PATH" from="INNERVAR"/>

<var varName="MY_REQUEST_HTTP_HOST_NAME" name="REQUEST_HTTP_HOST_NAME" from="INNERVAR"/>

<var varName="MY_PORT" name="REQUEST_HTTP_HOST_PORT" from="INNERVAR"/>

<var varName="MY_RESPONSE_ENDPOINT_ADDRESS" name="RESPONSE_ENDPOINT_ADDRESS" from="INNERVAR"/>

<var varName="MY_REQUEST_HTTP_HOST_PORT" name="REQUEST_HTTP_HOST_PORT" from="INNERVAR">

<regexTag>%MY_PORT%</regexTag>

<replaceTo>10100</replaceTo>

</var>

<var varName="MY_REQUEST_CLIENT_ADDRESS" name="REQUEST_CLIENT_ADDRESS" from="INNERVAR"/>

<var varName="MY_RESPONSE_ENDPOINT_ADDRESS" name="RESPONSE_ENDPOINT_ADDRESS" from="INNERVAR"/>

<var varName="MY_REQUEST_HTTP_COOKIES_LIST" name="REQUEST_HTTP_COOKIES_LIST" from="INNERVAR"/>

<!-- load variables from contant values -->

<var varName="MY_IS" name="is" from="CONSTANT"/>

<var varName="MY_VAR_FROM_THIS_VALUE" name="this is a my value %MY_REQUEST_HTTP_URL%" from="CONSTANT">

<regexTag>this %MY_IS% a my value</regexTag>

<replaceTo>this %MY_IS% a my value %MY_REQUEST_HTTP_HOST_PORT% HTTP_URL</replaceTo>

</var>

<!-- load variables from header entity -->

<var varName="MY_VAR_FROM_ENTITY" name="Connection" from="ENTITY">

<regexTag>Keep-alive</regexTag>

<replaceTo>Close</replaceTo>

</var>

<!-- load variables from uri params or query string -->

<var varName="MY_PROCESS" name="process" from="URI_PARAM"/>

<var varName="MY_PARAM" name="paramName" from="URI_PARAM">

<regexTag>valueInParamQueryString</regexTag>

<replaceTo>newValueInVar</replaceTo>

</var>

<!-- extract cookie value -->

<var varName="MY_VAR_COOKIE_LBLSESSIONID" name="LBLSESSIONID" from="COOKIE"/>

<var varName="MY_VAR_COOKIE_TCOPROJECTAUTH" name="TCOPROJECTAUTH" from="COOKIE"/>

<var varName="MY_VAR_COOKIE_TCOPROJECTSESSIONID" name="TCOPROJECTSESSIONID" from="COOKIE"/>

<var varName="MY_VAR_COOKIE_JSESSIONID" name="JSESSIONID" from="COOKIE"/>

<var varName="MY_VAR_COOKIE_jsessionid" name="jsessionid" from="COOKIE"/>

<var varName="MY_VAR_COOKIE_NOTFOUND" name="NOTFOUND" from="COOKIE"/>

<!-- only cookies list names -->

<var varName="MY_REQUEST_HTTP_COOKIES_LIST000" name="REQUEST_HTTP_COOKIES_LIST" from="INNERVAR">

<regexTag>(.*)(LBLSESSIONID)(.*)</regexTag>

<replaceTo>$2</replaceTo>

</var>

<var varName="MY_REQUEST_HTTP_COOKIES_LIST001" name="REQUEST_HTTP_COOKIES_LIST" from="INNERVAR">

<regexTag>(.*)(TCOPROJECTAUTH)(.*)</regexTag>

<replaceTo>$2</replaceTo>

</var>

<var varName="MY_REQUEST_HTTP_COOKIES_LIST002" name="REQUEST_HTTP_COOKIES_LIST" from="INNERVAR">

<regexTag>(.*)(TCOPROJECTSESSIONID)(.*)</regexTag>

<replaceTo>$2</replaceTo>

</var>

<!-- extract cookies from entity -->

<var varName="MY_VAR_COOKIES" name="Cookie" from="ENTITY">

<regexTag>(.+)</regexTag>

<replaceTo>$1;</replaceTo>

</var>

<!-- extract cookies from entity through variable -->

<var varName="MY_VAR_COOKIE_LBLSESSIONID_FV00" name="MY_VAR_COOKIES" from="VARIABLE">

<regexTag>(.*)(LBLSESSIONID=)(.+?)((;+?)(.*))</regexTag>

<replaceTo>$3</replaceTo>

</var>

<var varName="MY_VAR_COOKIE_LBLSESSIONID_FV01" name="MY_VAR_COOKIES" from="VARIABLE">

<regexTag>(.*)(TCOPROJECTAUTH=)(.+?)((;+?)(.*))</regexTag>

<replaceTo>$3</replaceTo>

</var>

<var varName="MY_VAR_COOKIE_LBLSESSIONID_FV02" name="MY_VAR_COOKIES" from="VARIABLE">

<regexTag>(.*)(TCOPROJECTSESSIONID=)(.+?)((;+?)(.*))</regexTag>

<replaceTo>$3</replaceTo>

</var>

</variables>

<conditions operator="AND">

<cond enable="false" from="COOKIE" name="LBLSESSIONID" eval="NOT">

<regexTag></regexTag>

</cond>

<cond from="VARIABLE" name="MY_IS" caseSensitive="true">

<regexTag>is</regexTag>

</cond>

<cond from="INNERVAR" name="REQUEST_HTTP_HOST_NAME">

<regexTag>www.tcoproject.dev</regexTag>

</cond>

<cond enable="false" from="INNERVAR" name="REQUEST_CLIENT_ADDRESS">

<regexTag>127.0.0.1</regexTag>

</cond>

<cond from="INNERVAR" name="REQUEST_HTTP_URL" caseSensitive="true">

<regexTag>^/viewProcessProperties.html\?process=A05_LBLGoDNSManager$</regexTag>

</cond>

<cond from="INNERVAR" name="REQUEST_HTTP_URI_PATH">

<regexTag>^/viewProcessProperties.html$</regexTag>

</cond>

<cond from="ENTITY" name="Connection">

<regexTag>Keep-alive</regexTag>

</cond>

<cond from="URI_PARAM" name="process">

<regexTag>A05_LBLGoDNSManager</regexTag>

</cond>

</conditions>

<redirectTo responseCode="302"

redirectURL="http://www.tcoproject.dev/trainingw?http://%MY_REQUEST_HTTP_HOST_NAME%:%MY_REQUEST_HTTP_HOST_PORT%/mynew path"/>

</rewriteHeaderRule>

 

HTTP HEADER Rewriting with extended JAVA classes

Come visto in precedenza è possibile indicare in una regola l’utilizzo di una classe in JAVA definita e scritta dall’utilizzatore.

Questa funzionalità può essere utilizzata contemporaneamente a quanto visto fino ad ora in quanto la classe è una estensione di una classe appositamente creata in LBL ADC a questo scopo. La classe mette a disposizione 6 momenti (metodi):

1-interceptorInit (richiamato una sola volta all’inizializzazione dell’oggetto)

2-interceptorEnd (richiamato una sola volta alla terminazione dell’oggetto)

3-doRequestHeaderBeforeReplace

4-doRequestHeaderAfterReplace

5-doResponseHeaderBeforeReplace

6-doResponseHeaderAfterReplace

package loadbalancer.rewriter;

import loadbalancer.rewriter.LBLHTTPInterceptorHeaderAbstr;

import loadbalancer.rewriter.LBLHTTPInterceptorHeaderStreamFragment;

/**

* Test class HTTP HEADER Interceptor for dynamic change during stream...

* @version 1.0 Created on 5-jun-2010

*/

public class LBLHTTPRewriteInterceptorHeaderLogging extends LBLHTTPInterceptorHeaderAbstr {

/** copyright */

public static final String COPYRIGHT="LBL and TCOProject are trademarks all rights reserved";

@Override

public void interceptorInit() {

}

@Override

public void interceptorEnd() {

}

@Override

public void doRequestHeaderBeforeReplace(LBLHTTPInterceptorHeaderStreamFragment streamFragment) {

logWarning("REQUEST HEADER BEFORE REPLACE\n"+

streamFragment.getRequestRowImageStreamFragment());

for (String varName: streamFragment.getVariables())

logWarning("RQBR HEADER VarName:"+varName+

" value:"+streamFragment.getVariable(varName));

}

@Override

public void doRequestHeaderAfterReplace(LBLHTTPInterceptorHeaderStreamFragment streamFragment) {

logWarning("REQUEST HEADER AFTER REPLACE\n"+

streamFragment.getRequestRowImageStreamFragment());

}

@Override

public void doResponseHeaderBeforeReplace(LBLHTTPInterceptorHeaderStreamFragment streamFragment) {

logWarning("RESPONSE HEADER BEFORE REPLACE\n"+

streamFragment.getResponseRowImageStreamFragment());

for (String varName: streamFragment.getVariables())

logWarning("REBR HEADER VarName:"+varName+

" value:"+streamFragment.getVariable(varName));

}

@Override

public void doResponseHeaderAfterReplace(LBLHTTPInterceptorHeaderStreamFragment streamFragment) {

logWarning("RESPONSE HEADER AFTER REPLACE\n"+

streamFragment.getResponseRowImageStreamFragment());

}

}

 

Inseriti nel nostro “ingranaggio” i metodi verranno richiamati nella sequenza sotto esposta, ovviamente se non sono state dichiarate via XML o comandate attraverso programma JAVA dei redirect. In quel caso alcuni di questi metodi non verrano richiamati.

All’interno di ogni metodo viene messo a disposizione un oggetto che rappresenta il “frammento” consistente di quanto sta transitando.

Nell’esempio visto in precedenza, e disponibile da libreria LBL ADC, all’interno di ogni metodo venivano eseguite alcune azioni come quella evidenziata di seguito:

@Override

public void doRequestHeaderBeforeReplace(LBLHTTPInterceptorHeaderStreamFragment streamFragment) {

logWarning("REQUEST HEADER BEFORE REPLACE\n"+

streamFragment.getRequestRowImageStreamFragment());

for (String varName: streamFragment.getVariables())

logWarning("RQBR HEADER VarName:"+varName+

" value:"+streamFragment.getVariable(varName));

}

 

La classe LBLHTTPInterceptorHeaderAbstr mette infatti a disposizione alcuni metodi e tra questi la possibilità di effettuare il log direttamente sul sistema di logging di LBL ADC.

/**

* generazione di un messaggio con tipologia |ERROR|

* @param logMessage messaggio da persistere su file di log

*/

public void logError(String logMessage)

/**

* generazione di un messaggio con tipologia |WARNING|

* @param logMessage messaggio da persistere su file di log

*/

public void logWarning(String logMessage)

/**

* generazione di un messaggio con tipologia |DEBUG| solo se definizione di lancio
* java ... -DDEBUG=true -DLBL_DEBUG_REWRITING=true ...

* @param logMessage messaggio da persistere su file di log

*/

public void logDebug(String logMessage)

 

In questo caso dal frammento di HEADER, passato come parametro al metodo, è possibile richiedere di elencare la lista delle variabili dichiarate e utilizzarne il valore:

for (String varName: streamFragment.getVariables())

logWarning(“RQBR HEADER VarName:”+varName+” value:”+streamFragment.getVariable(varName));

Altri metodi di interrogazione e manipolazione dei dati sono disponibili sull’oggetto streamFragment come ad esempio quelli relativi alla gestione degli ENTITIES:

// ********************************************************

// ENTITIES

// *******************************************************

/**

* get entity value

* @param entityName entity name es.: Content-Type

* @return entity value or null if not match

*/

public String getHTTPEntity(String entityName)

/**

* Remove an enity

* @param entityName

*/

public void removeEntity(String entityName)

/**

* Append an entity

* Warning: this method doesn't remove any entity... use changeEntity for change it.

* @param entity

*/

public void appendEntity(String entityName, String entityValue)

/**

* Change an entity

* @param entity

*/

public void changeEntity(String entityName, String entityValue)

/**

* Replace first line

* @param firstLineHeader new first header line

*/

public void changeFirstHeaderLine(String firstLineHeader)

 

Un elenco completo dei metodi è disponibile nel manuale LBL ADC Reference Guide.

La posizione delle classi è dipendente dal nome del package che verrà utilizzato e sarà relativo alla directory (vedere capitolo Create a JAVA extended class in questo manuale):

HTTP HEADER Rewriting displace endPointsGrouping

Con questa direttiva è possibile spiazzare in un altro EndPointsGrouping una richiesta proveniente da un listener afferente ad un EndPointsGrouping differente.

Questa funzionalità si ottiene utilizzando le regole di rewriting dell’Header con un nuovo paragrafo che indica l’azione di spiazzamento.

La forma più semplice è di seguito riportata:

<rewriteHeaderRule enable="true" flow="REQUEST" name="setEndpGrouping">

<displaceEndPointsGrouping enable="true" endPointsGrouping="services001"/>

</rewriteHeaderRule>

 

Il paragrafo <displaceEndPointsGrouping> (displace = spiazzamento) indica dove la richiesta deve fare riferimento come endPointsGrouping.

E’ possibile utilizzare tutte le forme gia’ previste per la composizione dello spiazzamento come ad esempio le variabili e le condizioni:

<rewriteHeaderRule enable="true" flow="REQUEST" name="setEndpGrouping">

<variables>

<var varName="DISPLACE_TO_GROUP" name="services001" from="CONSTANT"/>

</variables>

<displaceEndPointsGrouping enable="true" endPointsGrouping="%DISPLACE_TO_GROUP%"/>

</rewriteHeaderRule>

 

Il displace e’ possibile comandarlo anche da classe interceptor HEADER Java:

<rewriteHeaderRule enable="false" flow="REQUEST" name="setEndpGrouping"

httpInterceptorClass="my_httprewriters.LBLDisplaceEndPointGroupingTemplate">

</rewriteHeaderRule>

import loadbalancer.rewriter.LBLHTTPInterceptorHeaderAbstr;

import loadbalancer.rewriter.LBLHTTPInterceptorHeaderStreamFragment;

/**

* Template interceptor class for displace EndPointsGrouping

* @author TCOProject(r)

* @version 1.0 Created on 12-feb-2011, 17.04.05

*/

public class LBLDisplaceEndPointGroupingTemplate extends LBLHTTPInterceptorHeaderAbstr

{

…

…

@Override

public void doRequestHeaderBeforeReplace(LBLHTTPInterceptorHeaderStreamFragment streamFragment) {

streamFragment.setEndPointsGrouping("services001");

}

@Override

public void doRequestHeaderAfterReplace(LBLHTTPInterceptorHeaderStreamFragment streamFragment) {

}

@Override

public void doResponseHeaderBeforeReplace(LBLHTTPInterceptorHeaderStreamFragment streamFragment) {

}

@Override

public void doResponseHeaderAfterReplace(LBLHTTPInterceptorHeaderStreamFragment streamFragment) {

}

}

 

HTTP BODY Rewriting

Il rewriting del BODY HTTP è attualmente quanto di più sofisticato si possa utilizzare in questo campo. E’ possibile utilizzare contemporaneamente sia regole descrittive sia estensioni di classi JAVA o di scripting. In entrambi i casi i dati vengono “passati” al rewriter con buffer consistenti per poter applicare espressioni regolari di modificazione.

L’utilizzo delle regole di rewriting per il BODY è simile all’utilizzo delle regole di rewriting dell’HEADER e quindi una volta utilizzate le une o le altre si è rapidamente in grado di utilizzarle entrambe.

Riprendiamo il frammento di regole iniziale per andare ad effettuare il primo rewriting del BODY.

<rewriteManagement>

<rewriteHeaderRule name=”fromHttpsToHttp302”>

</rewriteHeaderRule>

<rewriteHeaderRule name=”fromHttpsToHttp301”>

</rewriteHeaderRule>

...

...

<rewriteBodyRule name=”changeColor”>

</rewriteBodyRule>

<rewriteBodyRule name=”tcoprojectDevToRelative”>

</rewriteBodyRule>

...

...

</rewriteManagement>

 

 

Anche in questo caso i parametri iniziali sono identici al paragrafo <rewriteHeaderRule> e prevedono una identificazione della regola attraverso un nome simbolico dichiarato sul parametro “name”, una indicazione del flusso dati che si vuole intercettare, parametro “flow” e delle condizioni di base come il metodo HTTP utlizzato nella request o il response code in risposta dal servizio per arrivare al nostro esempio con questi parametri:

<rewriteManagement>

<rewriteHeaderRule name=”fromHttpsToHttp302”>

</rewriteHeaderRule>

<rewriteHeaderRule name=”fromHttpsToHttp301”>

</rewriteHeaderRule>

...

...

<rewriteBodyRule flow="RESPONSE" name="changeColor""

httpMethod="GET"

responseCode="200">

</rewriteBodyRule>

<rewriteBodyRule flow="RESPONSE" name="tcoprojectDevToRelative">

</rewriteBodyRule>

...

...

</rewriteManagement>

 

 

Il nome indica volutamente l’azione che si vuole intraprendere, nella prima regola si vuole cambiare il colore di un elemento all’interno di un css noto mentre nel secondo si vuole genericamente trasportare da hyperlink assoluti a hyperlink relativi un BODY che viene erogato da un servizio posto nel backend.

Cominceremo con la prima regola di rewriting ad identificare il nome della risorsa css che è il depositario del dato del colore. Identificato in “styles.css” possiamo andare a comporre la nostra regola con questa condizione:

...

...

<rewriteBodyRule flow="RESPONSE" name="changeColor"

httpMethod="GET"

responseCode="200">

<requestURLMatches>styles.css</requestURLMatches>

</rewriteBodyRule>

...

 

il paragrafo <requestURLMatches> è un facilitatore di condizione. Verifica con una espressione regolare se il valore è verificato all’interno dell’URL. In questo caso all’interno dell’URL deve essere presente la risorsa “styles.css”.

Una volta identificata la risorsa dobbiamo istruire il rewriter del tipo di mime type associato.

...

...

<rewriteBodyRule flow="RESPONSE" name="changeColor"

httpMethod="GET"

responseCode="200">

<requestURLMatches>styles.css</requestURLMatches>

<mimeType enable="true" value="text/css" fragmentClose="}" fragmentOpen="{"/>

</rewriteBodyRule>

...

 

Questa associazione nel caso del rewriting del BODY non è facoltativa perché in base al mime type si identificano i blocchi di rewriting consistenti attraverso i parametro fragmentClose e fragmentOpen. E’ importante stabilire il blocco consistente di modifica perchè il “frammentatore” del rewriter del BODY renderà disponibile alle espressioni regolari descritte sul file XML o al alla esetensione della classe JAVA solo porzioni modificabili e consistenti da un punto di vista logico.

Se prendiamo ad esempio la risorsa sopra descritta il suo contenuto originale potrebbe essere il seguente:

/* Linee di inclusione titolo e bottom della pagina */

td.EncloserLine {

height: 2px;

background-color: rgb(51, 51, 255);

}

/* Tabella di contenuti */

table.ContentTable {

text-align: left;

width: 100%;

}

/* titolo del paragrafo */

td.ParagraphTitle {

text-align: left;

color: black;

font-weight: bold;

font-style: italic;

background-color: rgb(255, 143, 89);

}


/* corpo del paragrafo */

td.ParagraphBody {

text-align: left;

}

 

Appare chiaro che volendo modificare dei valori all’interno delle parentesi graffe la sola possibilità offerta è di rendere disponibili dei buffer che contengano sempre un blocco che non spezzi in due il contenuto tra queste parentesi durante il trasferimento. Così facendo e volendo modificare il valore 255 in 100 non si dovrà mai presentare la seguente situazione con un primo buffer valorizzato a…

/* Linee di inclusione titolo e bottom della pagina */

td.EncloserLine {

height: 2px;

background-color: rgb(51, 51, 255);}

 

ed un secondo buffer con il contenuto restante.

/* Tabella di contenuti */

table.ContentTable {

text-align: left;

width: 100%;

}

/* titolo del paragrafo */

td.ParagraphTitle {

text-align: left;

color: black;

font-weight: bold;

font-style: italic;

background-color: rgb(255, 143, 89);

}


/* corpo del paragrafo */

td.ParagraphBody {

text-align: left;

}

 

Il blocco consistente in questo caso poteva essere identificato anche nelle parentesi rotonde, infatti il valore che si vuole modificare è sempre compreso in un blocco consistente racchiuso da parentesi rotonde.

E’ stata lasciata ampia libertà di scegliere la definizione di blocco consistente proprio per poter adattare al meglio la propria regola. Ovviamente le best practices indicano come blocco consistente per html e xml le parentesi angolari, “<” “>”, per i css le parentesi graffe, “{“ ”}”, per i parametri all’interno di un body prodotto da una form HTTP (application/x-www-form-urlencoded) le “&” che suddividono i parametri con il loro nome=valore;

Nel caso del css quindi imposteremo un mime type di tipo “text/css” con parentesi graffe e per il rewriting da hipelink assoluto a relativo indicheremo un mime type di tipo “text/html” con parentesi angolari. Essendo le parentesi angolari una keyword riservata di XML si dovranno inserire al loro posto fragmentClose=“&gt;” e fragmentOpen=”&lt;” (vedere manuale XML per le altre definizioni).

Le nostre regole quindi assumono questo aspetto:

<rewriteManagement>

...

<rewriteBodyRule flow="RESPONSE" name="changeColor""

httpMethod="GET"

responseCode="200">

<requestURLMatches>styles.css</requestURLMatches>

<mimeType enable="true" value="text/css" fragmentClose="}" fragmentOpen="{"/>

</rewriteBodyRule>

<rewriteBodyRule flow="RESPONSE" name="tcoprojectDevToRelative">

<requestURLMatches>/TESTRewrite.html</requestURLMatches>

<mimeType enable="true" value="text/html" fragmentClose="&gt;" fragmentOpen="&lt;"/>

</rewriteBodyRule>

...

</rewriteManagement>

 

 

A questo punto se le condizioni “facilitate” bastano a verificare l’applicabilità della regola è sufficiente applicare la regola di rewriting aggiungendola con i paragrafi <regexTag> e <replaceTo> rispettivamente sulla regola changeColor e tcoprojectDevToRelative.

<rewriteManagement>

...

<rewriteBodyRule flow="RESPONSE" name="changeColor""

httpMethod="GET"

responseCode="200">

<requestURLMatches>styles.css</requestURLMatches>

<mimeType enable="true" value="text/css" fragmentClose="}" fragmentOpen="{"/>

<regexTag>255</regexTag>

<replaceTo>100</replaceTo>

</rewriteBodyRule>

<rewriteBodyRule flow="RESPONSE" name="tcoprojectDevToRelative">

<requestURLMatches>/TESTRewrite.html</requestURLMatches>

<mimeType enable="true" value="text/html" fragmentClose="&gt;" fragmentOpen="&lt;"/>

<regexTag>(href|src)=\"(http|https)://www.tcoproject.dev/</regexTag>

<replaceTo>$1=\"</replaceTo>

</rewriteBodyRule>

...

</rewriteManagement>

 

Mentre la prima espressione regolare è abbastanza intuitiva, anche se non scontata in quanto questa regola cambia tutti i valori 255 incontrati con 100 potendo causare delle modifiche inopportune, la seconda appare abbastanza articolata. Ovviamente si rimanda alla documentazione delle espressioni regolari, molto consistente in Internet, ma proveremo a dare una rapida spiegazione:

L’espressione regolare

(href|src)=\"(http|https)://www.tcoproject.dev/

indica:

per ugualianze di stringhe:

href=”http://www.tcoproject.dev/

oppure

src=”http://www.tcoproject.dev/

oppure

href=”https://www.tcoproject.dev/

oppure

src=”https://www.tcoproject.dev/

si modifichi con il risultato del primo insieme attraverso l’espressione

$1=\”

Questa espressione indica con $1 il risultato del contenuto del primo insieme (href|src) e quindi aggiunge le costanti =”.

Il risultato finale cambierà un eventuale valore

da

href=”http://www.tcoproject.dev/training

in

href=”/training

Di seguito un altro esempio di cambiamento del BODY che cambia tutte le parole incontrate con “WARNING” maiuscolo e le modifica in “ATTENZIONE”:

<rewriteBodyRule enable="true" flow="RESPONSE" name="traduci" caseSensitive="true">

<mimeType enable="true" value="text/html" fragmentClose="&gt;" fragmentOpen="&lt;"/>

<conditions operator="AND">

<cond from="INNERVAR" name="REQUEST_HTTP_URL">

<regexTag>^/viewLogFile.html</regexTag>

</cond>

</conditions>

<regexTag>WARNING</regexTag>

<replaceTo>ATTENZIONE</replaceTo>

</rewriteBodyRule>

 

Il risultato di tale operazione si può apprezzare utilizzando tutte le regole viste fino a questo momento, comprese le regole di rewriting dell’HEADER per passare da un servizio che colloquia in HTTPS (SSL) a un client che comunica attraverso HTTP:

Non passando attraverso il rewriter…

Passando attraverso il rewriter:

HTTP BODY Rewriting with VARIABLES

Come nell’HEADER anche nel BODY possono essere utilizzate le variabili per comporre dei nuovi valori da utilizzarsi nelle modifiche dei contenuti.

Con le stesse regole applicate sulle espressioni regolari relative al body, di seguito un esempio di minima che utilizza le variabili:

<rewriteBodyRule enable="true" flow="RESPONSE" name="LBL" caseSensitive="false">

<mimeType enable="true" value="text/html" fragmentClose="&gt;" fragmentOpen="&lt;"/>

<variables>

<var varName="MY_VAR_FROM_THIS_VALUE" name="LBL the best! " from="CONSTANT">

</var>

</variables>

<regexTag>LBL\(r\)</regexTag>

<replaceTo>%MY_VAR_FROM_THIS_VALUE%</replaceTo>

</rewriteBodyRule>

 

HTTP BODY Rewriting with extended JAVA classes

Anche con la funzionalità di rewriting del BODY è possibile contemporaneamente utilizzare il rewriting attraverso regole descritte sul file XML e associare anche una estensione di una classe JAVA appositamente resa disponibile dalla libreria con i seguenti metodi:

1-doRequestBodyBeforeReplace

2-doRequestBodyAfterReplace

3-doResponseBodyBeforeReplace

4-doResponseAfterAfterReplace

Anche in questo caso la classe mette a disposizione dei metodi i frammenti consistenti di BODY dove è possibile intervenire bit a bit con modifiche o verifiche di contenuti.

package loadbalancer.rewriter;

import loadbalancer.rewriter.LBLHTTPInterceptorBodyAbstr;

import loadbalancer.rewriter.LBLHTTPInterceptorBodyStreamFragment;

/**

* Test class HTTP BODY Interceptor for dynamic change during stream...

* @version 1.0 Created on 5-jun-2010

*/

public class LBLHTTPRewriteInterceptorBodyLogging extends LBLHTTPInterceptorBodyAbstr {

/** copyright */

public static final String COPYRIGHT="LBL and TCOProject are trademarks all rights reserved";

/**

* Metodo richiamato alla richiesta del client prima di effettuare le modifiche ad opera delle espressioni regolari

* @param streamFragment frammento consistente del body (HTML/CSS/JS etc)

*/

@Override

public void doRequestBodyBeforeReplace(LBLHTTPInterceptorBodyStreamFragment streamFragment) {

logWarning("REQUEST BODY BEFORE REPLACE\n"+streamFragment.getStreamFragment());

for (String varName: streamFragment.getVariables())

logWarning("RQBR BODY VarName:"+varName+" value:"+streamFragment.getVariable(varName));

}

/**

* Metodo richiamato alla richiesta del client dopo aver effettuato le modifiche ad opera delle espressioni regolari

* @param streamFragment frammento consistente del body (HTML/CSS/JS etc)

*/

@Override

public void doRequestBodyAfterReplace(LBLHTTPInterceptorBodyStreamFragment streamFragment) {

logWarning("REQUEST BODY AFTER REPLACE\n"+streamFragment.getStreamFragment());

}

/**

* Metodo richiamato al response del servizio prima di effettuare le modifiche ad opera delle espressioni regolari

* @param streamFragment frammento consistente del body (HTML/CSS/JS etc)

*/

@Override

public void doResponseBodyBeforeReplace(LBLHTTPInterceptorBodyStreamFragment streamFragment) {

logWarning("RESPONSE BODY BEFORE REPLACE\n"+streamFragment.getStreamFragment());

for (String varName: streamFragment.getVariables())

logWarning("REBR BODY VarName:"+varName+" value:"+streamFragment.getVariable(varName));

}

/**

* Metodo richiamato al response del servizio dopo aver effettuato le modifiche ad opera delle espressioni regolari

* @param streamFragment frammento consistente del body (HTML/CSS/JS etc)

*/

@Override

public void doResponseBodyAfterReplace(LBLHTTPInterceptorBodyStreamFragment streamFragment) {

logWarning("RESPONSE BODY AFTER REPLACE\n"+streamFragment.getStreamFragment());

}

}

 

A differenza dell’HEADER il BODY da un punto di vista prettamente tecnologico il flusso dati verrà passato per “blocchi” consistenti e non per intero contenuto. Questo sarà assolutamente trasparente per colui che si accinge a scrivere la regola di rewriting e sarà automatizzato dal rewriter mantenendo consistente il frammento attraverso i caratteri descritti in fragmentOpen e fragmentClose.

Sul BODY sono stati resi disponibili metodi differenti di interazione con il frammento, alcuni sono comuni altri sono ovviamente tipici per il trattamento del BODY. Forse uno tra i più interessanti è l’interazione con i valori contenuti in un BODY e forniti da una FORM HTML.

package testrewrite;

import loadbalancer.rewriter.LBLHTTPInterceptorBodyAbstr;

import loadbalancer.rewriter.LBLHTTPInterceptorBodyStreamFragment;

/**

* Test class HTTP Interceptor for dynamic change during stream...

* @version 1.0 Created on 20-mag-2010

*/

public class HTTPRewriteInterceptorBodyAddParam extends LBLHTTPInterceptorBodyAbstr {

/** copyright */

public static final String COPYRIGHT="LBL and TCOProject are trademarks all rights reserved";

/**

* Metodo richiamato alla richiesta del client prima di effettuare le modifiche ad opera delle espressioni regolari

* @param streamFragment frammento consistente del body (HTML/CSS/JS etc)

*/

@Override

public void doRequestBodyBeforeReplace(LBLHTTPInterceptorBodyStreamFragment streamFragment) {

logDebug("REQUEST BEFORE REPLACE\n"+streamFragment.getStreamFragment());

// INSERIMENTO DI UN NUOVO PARAMETRO NEL BODY!!!!

streamFragment.addParameterInTheBody("COPYRIGHT", "LBL and TCOProject are trademarks all rights reserved");

}

/**

* Metodo richiamato alla richiesta del client dopo aver effettuato le modifiche ad opera delle espressioni regolari

* @param streamFragment frammento consistente del body (HTML/CSS/JS etc)

*/

@Override

public void doRequestBodyAfterReplace(LBLHTTPInterceptorBodyStreamFragment streamFragment) {

logDebug("REQUEST AFTER REPLACE\n"+streamFragment.getStreamFragment());

}

/**

* Metodo richiamato al response del servizio prima di effettuare le modifiche ad opera delle espressioni regolari

* @param streamFragment frammento consistente del body (HTML/CSS/JS etc)

*/

@Override

public void doResponseBodyBeforeReplace(LBLHTTPInterceptorBodyStreamFragment streamFragment) {

logDebug("RESPONSE BEFORE REPLACE\n"+streamFragment.getStreamFragment());

}

/**

* Metodo richiamato al response del servizio dopo aver effettuato le modifiche ad opera delle espressioni regolari

* @param streamFragment frammento consistente del body (HTML/CSS/JS etc)

*/

@Override

public void doResponseBodyAfterReplace(LBLHTTPInterceptorBodyStreamFragment streamFragment) {

logDebug("RESPONSE AFTER REPLACE\n"+streamFragment.getStreamFragment());

}

}

 

La regola XML per inserire ad ogni POST HTTP il nuovo parametro sarà:

<rewriteBodyRule enable="true" flow="REQUEST" name="addTrademarkParam" caseSensitive="false"

httpMethod="POST"

httpInterceptorClass="testrewrite.HTTPRewriteInterceptorBodyAddParam">

<mimeType enable="true"

value="application/x-www-form-urlencoded" fragmentClose="&amp;" fragmentOpen="&amp;"/>

</rewriteBodyRule>

In questo caso l’azione di rewriting verrà interamente svolta dall’estensione della classe JAVA ed il risultato sarà un aggiunta di un parametro al Form HTML esistente:

39|20100607-09:40:53|A HTTP Method=POST||

54|20100607-09:40:53|A HTTP URL request/papaia/ServletSession||

54|20100607-09:40:53|A Parameter Service name=null||

54|20100607-09:40:53|A Request address=127.0.0.1||

54|20100607-09:40:53|A Response address=127.0.0.1||

54|20100607-09:40:53|A Paramname=applicationId value=9EFCE61F5A8582BAE219CB720FCE33CE-PapaiaLoaderId-6781414||

54|20100607-09:40:53|A Paramname=jprogram value=asstec.programs.JTUSecond||

54|20100607-09:40:53|A Paramname=TransactionButton.Trash value=Cancella||

54|20100607-09:40:53|A Paramname=area1.cod_cli value=Mango||

54|20100607-09:40:53|A Paramname=area1.data_nascita value=01/01/1964||

54|20100607-09:40:53|A Paramname=area1.address value=Via estate, 2010||

54|20100607-09:40:53|A Paramname=area1.nota value=Test||

54|20100607-09:40:53|A Paramname=COPYRIGHT value=LBL and TCOProject are trademarks all rights reserved||

70|20100607-09:40:53|B 11||

70|20100607-09:40:53|B POST||

70|20100607-09:40:53|B /papaia/ServletSession||

70|20100607-09:40:53|B Paramname=applicationId value=9EFCE61F5A8582BAE219CB720FCE33CE-PapaiaLoaderId-6781414||

70|20100607-09:40:53|B Paramname=jprogram value=asstec.programs.JTUSecond||

70|20100607-09:40:53|B Paramname=TransactionButton.Trash value=Cancella||

70|20100607-09:40:53|B Paramname=area1.cod_cli value=Papaia||

70|20100607-09:40:53|B Paramname=area1.data_nascita value=01/01/1964||

85|20100607-09:40:53|B Paramname=area1.address value=Via SnowBoard, 2010||

85|20100607-09:40:53|B Paramname=area1.nota value=Biancaneve||

85|20100607-09:40:53|B Paramname=COPYRIGHT value=LBL and TCOProject are trademarks all rights reserved||

85|20100607-09:40:53|LBLSESSIONID>>>>1276185123144||

85|20100607-09:40:53|TCOPROJECTAUTH>>>>null||

ATTENZIONE:

Alcuni application server non supportano il metodo POST con “transfer-encoding: chunked”. Ad esempio Apache Tomcat ha risolto questo problema sicuramente dalla versione 6.0.26 con versioni inferiori (es.:6.0.14) non funziona. Accertarsi che l’application server sia compliant alla raccomandazione HTTP1.1 transfer-encoding: chunked

Create JAVA extended class HTTP Interceptor

Per creare e compilare una estensione di classe JAVA in forma basilare è sufficiente:

1- andare nella directory: (LBL_HOME)\interceptors\rewriteclasses

2- Creare una classe come riportato in esempio:

package rewriteclasses

import loadbalancer.rewriter.LBLHTTPInterceptorBodyAbstr;

import loadbalancer.rewriter.LBLHTTPInterceptorBodyStreamFragment;

public class HTTPRewriteBody extends LBLHTTPInterceptorBodyAbstr {

@Override

public void doRequestBodyBeforeReplace(LBLHTTPInterceptorBodyStreamFragment streamFragment) {

logWarning("REQUEST ADDPARAM BEFORE REPLACE\n"+

new String(streamFragment.getStreamFragment()));

}

@Override

public void doRequestBodyAfterReplace(LBLHTTPInterceptorBodyStreamFragment streamFragment) {

logWarning("REQUEST ADDPARAM AFTER REPLACE\n"+

new String(streamFragment.getStreamFragment()));

}

@Override

public void doResponseBodyBeforeReplace(LBLHTTPInterceptorBodyStreamFragment streamFragment) {

logWarning("RESPONSE ADDPARAM BEFORE REPLACE\n"+

new String(streamFragment.getStreamFragment()));

}

@Override

public void doResponseBodyAfterReplace(LBLHTTPInterceptorBodyStreamFragment streamFragment) {

logWarning("RESPONSE ADDPARAM AFTER REPLACE\n"+

new String(streamFragment.getStreamFragment()));

}

}

4- Compilare il programma aiutandosi con un piccolo batch file per facilitare l’operazione

con i parametri contestualizzati nel proprio ambiente (esempio di file batch):

@ECHO OFF

SET PATH=C:\work1\bin\java\jdk1.6.0_11\bin;%PATH%

SET CLASSPATH=.;C:\work1\bin\LBLLoadBalancer\LBLLoadBalancer_enterprise_007_001_000\lib\LBLLoadBalancer.jar

JAVAC %*

#|/bin/sh

PATH=/work1/bin/java/jdk1.6.0_11/bin:$PATH

export PATH

CLASSPATH=.:/work1/bin/LBLLoadBalancer/LBLLoadBalancer_enterprise_007_001_000/lib/LBLLoadBalancer.jar

export CLASSPATH

javac $@

 

Con uno dei due batch file eseguire ad esempio: compila.bat HTTPRewriteBody.java

5- Creare una regola che preveda il programma appena creato:

<rewriteBodyRule flow="BOTH" name="myBodyTest"

httpInterceptorClass="testrewrite.HTTPRewriteBody">

</rewriteBodyRule>

 

6- Dichiarare su quali servizi applicare la regola:

<endpoints>

<endPointsGrouping enable="true">

<virtualDomain virtualDomainName="www.tcoproject.dev"

rewriteHeaderRules=""

rewriteBodyRules="traduci myBodyTest">

<endp address="legendonebackend" port="8181" uriPath="/papaia"/>

<endp address="legendonebackend" port="8181" uriPath="/prvSevletEcho"/>

<endp address="legendonebackend" port="8181" uriPath="/training"/>

<endp address="legendonebackend" port="8181" uriPath="/trainingw"/>

<endp address="legendonebackend" port="8282" uriPath="/papaia"/>

...

...

...

 

OPPURE:

<endpoints>

<endPointsGrouping enable="true">

<virtualDomain virtualDomainName="www.tcoproject.dev"

rewriteHeaderRules=""

rewriteBodyRules="traduci">

<endp address="legendonebackend" port="8181" uriPath="/papaia"/>

<endp address="legendonebackend" port="8181" uriPath="/prvSevletEcho"/>

<endp address="legendonebackend" port="8181" uriPath="/training"

rewriteBodyRules="myBodyTest"/>

<endp address="legendonebackend" port="8181" uriPath="/trainingw"/>

<endp address="legendonebackend" port="8282" uriPath="/papaia"/>

...

...

...

 

7- Stop e start del servizio per far acquisire nuovamente il parametro.

Create JAVA extended class TCP Interceptor

L’utilizzo delle classi di rewriting nei flussi layer 4 TCP mettono a disposizione dell’implementatore uno strumento potentissimo in grado di verificare e/o modificare i valori che attraversano lo strado di instradamento e bilanciamento. Le classi di rewriting permettono anche di effettuare delle considerazioni sui contenuti e instradare in maniera coerente le informazioni.

Il principio su cui si basa l’implementazione dellle classi di rewriting Layer 4 TCP è molto semplice. Alla dichiarazione del listener è possibile indicare una classe di rewriting che intercetterà l’innesco proveniente dal client e quindi lo stream bidirezionale full duplex. Di seguito un listener di esempio che si può trovare nel template messo a disposizione nella distribuzione nella directory: (LBL_HOME)/interceptors/rewriteclasses/LBLTCPRewriteInterceptorLogging.java.

<!-- RDP con session affinity -->

<bind listenType="NAT"

address="localhost" port="4389"

osiLayer="4"

protocol="rdp-session-affinity"

endPointsGrouping="rdp-service"

transport="tcp"

transportSessionAffinity="true"

distinguishSingleConnection="true"

tcpInterceptorClassPath="interceptors/"

tcpInterceptorClass="rewriteclasses.LBLTCPRewriteInterceptorLogging"

enable="true"/>

I parametri:

tcpInterceptorClassPath="interceptors/"

tcpInterceptorClass="rewriteclasses.LBLTCPRewriteInterceptorLogging"

indicano la classe che verrà utilizzata nel rewriting.

Le classi di rewriting estendono la classe astratta con 6 metodi di controllo di flusso:

loadbalancer.rewriter.LBLTCPRewriteInterceptorAbstr

@Override

public void interceptorInit(String processHomePath, String address, int port) {

}

@Override

public void interceptorEnd(String processHomePath, String address, int port) {

}

@Override

public boolean doPrimerFromClient(LBLTCPRewriteInterceptorFragment tcpFragment) {

return true;

}

@Override

public boolean doPacketFromClient(LBLTCPRewriteInterceptorFragment tcpFragment) {

return true;

}

@Override

public boolean doPacketFromEndpoint(LBLTCPRewriteInterceptorFragment tcpFragment) {

return true;

}

@Override

public boolean doPrimerFromEndpoint(LBLTCPRewriteInterceptorFragment tcpFragment) {

return true;

}

 

Il primo metodo viene richiamato dopo il primo innesco del client che intraprende la richiesta, il secondo metodo viene richiamato ad ogni pacchetto che transita dal client verso l’endpoint ed il terzo metodo viene richiamato ad ogni pacchetto che transita dall’endpoint verso il client. N.B.: I due metodi doPacketFromClient e doPacketFromEndpoint possono essere utilizzati anche contemporaneamente in quanto il flusso è full-duplex.

Al primo innesco (doPrimerFromClient), in dipendenza del protocollo, è possibile escludere la lettura del primo pacchetto proveniente dal client attraverso il parametro tcpInterceptorPrimerCapture=”false”. Questa funzionalità deve essere disabilitata in tutti i casi in cui si sta eseguendo il rewriting di protocolli che non prevedono un innesco da parte del client (es.: telnet). Il parametro tcpInterceptorPrimerCapture non ha alcun effetto se non viene esplicitamente utilizzata una classe di rewriting TCP.

LBLTCPRewriteInterceptorFragment tcpFragment

Il frammento passato nei metodi call-back permette di accede a diverse funzionalità di controllo e modifica di flusso. Di seguito un elenco di alcune delle funzioni messe a disposizione:

/**

* buffer stream getter

* @return buffer stream or null if error

*/

public byte[] getStream()

/**

* set a new stream buffer

* @param newBufferStream

* @throws IOException

*/

public void setStream(byte[] newBufferStream) throws IOException

/**

* return client host address

* @return client host address or null if not found

*/

public String getRequestClientAddress()

/**

* return incoming host address

* @return incoming host address or null if not found

*/

public String getRequestIncomingAddress()

/**

* return incoming socket

* @return incoming socket or null if not found

*/

public Socket getRequestIncomingSocket()

/**

* return incoming SSLSocket or null if not found or not SSL Socket

* @return incoming SSLSocket or null if not found or not SSL Socket

*/

public SSLSocket getRequestIncomingSSLSocket()

/**

* Session SSL socket connected to the incoming

* @return SSL session connected to the incoming socket,

* or null if no SSL or non-existent socket

*/

public SSLSession getRequestIncomingSSLSession()

/**

* Peer certificates connected to the incoming socket

* @return Peer certificates connected to the incoming socket,

* or null if no SSL or non-existent socket

*/

public java.security.cert.Certificate[] getRequestIncomingSSLCertificates()

/**

* return incoming host name or address

* @return incoming host host name or address or null if not found

*/

public String getRequestIncomingHostName()

/**

* client ssl connection

* @return true if client ssl connection

*/

public String isSSLClientConnection()

/**

* return endpoint socket

* @return endpoint socket or null if not found

*/

public Socket getResponseEndpointSocket()

/**

* return endpoint SSLSocket or null if not found or not SSL Socket

* @return endpoint SSLSocket or null if not found or not SSL Socket

*/

public SSLSocket getResponseEndpointSSLSocket()

/**

* SSL session connected to the incoming socket endpoint

* @return SSL session endpoints connected to the socket,

* or null if the incoming non-SSL sockets or nonexistent

*/

public SSLSession getResponseEndpointSSLSession()

/**

* Peer certificates connected to the socket endpoint

* @return Peer certificates connected to the socket endpoint,

* or null if no SSL or non-existent socket

*/

public java.security.cert.Certificate[] getResponseEndpointSSLCertificates()

/**

* return endpoint host address

* @return endpoint host address or null if not found

*/

public String getResponseEndpointAddress()

/**

* endpoint ssl connection

* @return true if endpoint ssl connection

*/

public String isSSLEndpointConnection()

/**

* ssl reencryption

* @return true if in ssl reencryption

*/

public String isSSLReencryptionConnection()

 

Create JAVA extended class UDP Interceptor

L’utilizzo di classi di rewriting nel forwarding dei pacchetti UDP è possibile impostando nel listener il riferimento alla classe di rewriting che si intende utilizzare.

La modalità è simile al rewriting TCP e l’impostazione della classe nel file parametri avviene nella seguente modalità. La classe impostata nell’esempio è compresa nella distribuzione in modalità sorgente nella directory:

(LBL_HOME)/interceptors/rewriteclasses/LBLUDPRewriteInterceptorLogging

<bind enable="true"

doubleIncomingQueues="false"

listenType="NAT"

description="First FWD"

address="localhost"

port="8888-8889"

osiLayer="4"

protocol="udp"

endPointsGrouping="udp-forward-group"

transportSessionAffinity="true"

transport="udp"

udpInterceptorClass="rewriteclasses .LBLUDPRewriteInterceptorLogging"/>

 

Anche con l’UDP è possibile impostare l’affinità di sessione, come da esempio.

Le classi di rewriting UDP estendono la classe con i seguenti metodi da implementare:

loadbalancer.rewriter.LBLUDPRewriteInterceptorAbstr

@Override

public void interceptorInit(String processHomePath, String address, int port) {

}

@Override

public void interceptorEnd(String processHomePath, String address, int port) {

}

@Override

public void doAfterReceivedUDPPacketFromClient(LBLUDPRewriteInterceptorFragment udpFragment) {

}

@Override

public void doAfterReceivedUDPPacketFromEndpoint(LBLUDPRewriteInterceptorFragment udpFragment) {

}

 

Dall’oggetto che viene passato come parametro delle funzioni è possibile ispezionare e variare sia i pacchetti che transitano sia variarne la loro destinazione.

Di seguito alcuni metodi messi a disposizione dall’oggetto che viene passato durante l’attraversamento del pacchetto.

/**

* input buffer. This is not a copy of buffer.

* Remind to setPacketLength after used the array.

* @return input buffer

*/

public byte[] getPacketByteArray()

/**

* Write pointer of the array

* @return Write pointer of the array

*/

public int getPacketLength()

/**

* Set a write pointer of the array

* @param wp write pointer

*/

public void setPacketLength(int wp)

/**

* endpoint address before rewriting

* @return the endpointAddress

*/

public InetAddress getEndPointAddress()

/**

* endpoint address before rewriting

* @param endPointAddress the endpointAddress to set

*/

public void setEndPointAddress(InetAddress endPointAddress)

/**

* Return a local incoming port

* @return local incoming port

*/

public int getLocalIncomingPort()

/**

* Return a local incoming Inet Address

* @return local incoming Inet Address

*/

public InetAddress getLocalIncomingInetAddress()

/**

* Return the host inet address of the client that sent the packet

* @returnhost inet address of the client that sent the packet

*/

public InetAddress getClientHostAddress()

 

LBL ADC: Sviluppo di regole integrato



Attraverso l’interfaccia grafica HTML 5 è possibile gestire l’intero ciclo di sviluppo delle regole evolute. Da interfaccia grafica è possibile eseguire l’editazione, la compilazione, l’import, l’export del codice mantenendo coerenza in caso di installazioni in cluster su più nodi.

LBL VAPP Developer: Sviluppo di regole integrato

Per uno sviluppo avanzato di regole è disponibile il download gratuito di un ambiente virtuale che permette di sviluppare e provare regole di rewriting prima di applicarle in produzione.

Il sistema è stato concepito per ambienti Enterprise e può essere configurato per supportare processi di certificazione delle regole sviluppate fino alla creazione di ambienti di software versioning, test, stage, e rilascio.

Con LBL®Developer è possibile accentrare politiche di security, sistemi di SSO, integrazioni di terze parti in modo semplice, verificabile passo passo, riproducibile e visuale.

ENABLE REWRITING TRACE

L’abilitazione del trace delle funzionalità di rewriting è possibile attraverso due definizioni allo start della JVM.

E’ possibile tracciare solo gli eventi, come il caricamento delle variabili e la verifica delle condizioni, oppure eseguire anche il trace delle trasformazioni apportate.

Per attivare i due trace è possibile utilizzare le seguenti definizioni di start:

-DLBL_DEBUG_REWRITING (abilita il trace del rewriting durante i test delle

condizioni e il caricamento delle variabili)

-DLBL_DEBUG_ROW_REWRITING (abilita il trace del rewriting dei frammenti di

stream prima e dopo le modifiche

ATTENZIONE: questo flag se abilitato

esegue un log molto voluminoso,

abilitare in fase di debug delle regole)

Per poterli attivare e’ necessario in fase di lancio impostare il processo in debug con la definizione -DDEBUG=true eseguire ad es.:

java -server …. -DDEBUG=true -DLBL_DEBUG_REWRITING=true -DLBL_DEBUG_ROW_REWRITING=true

Conclusione

Le funzionalità di rewriting implementate in LBL ADC sono tra le più complete per un mercato professionale. Questo documento, assieme al documento LBL ADC Reference Guide, danno un’idea della potenza applicabile in diverse situazioni e contesti mantenendo contemporaneamente controllo ed auto documentando quanto sviluppato attraverso la raffinata espressività del paradigma XML o del linguaggio Java.

Sei interessato alle nostre soluzioni?