Protheus e AdvPL ASP – Parte 05

Introdução

No post anterior (Protheus e AdvPL ASP – Parte 04), vimos mais dois alias virtuais — HTTPHEADIN e HTTPHEADOUT. Agora, vamos ver o alias virtual HTTPCOOKIES, que permite lidar diretamente com Cookies de seção, e depois algumas propriedades estendidas ou campos reservados de cada um dos alias virtuais do AdvPL ASP.

Quer ler sobre esse assunto desde o início?
Veja os links de referência no final do post.

O que é um Cookie ?

Bem superficialmente, um Cookie é um fragmento de dados enviado por um Web Server ao Web Browser (ou Client), que é transmitido de volta pelo Client ao Web Server em próximas requisições. Recomendo a leitura do documento “Cookies HTTP“, ele explica bem os tipos de Cookies, escopo, persistência, utilização, e inclusive como evitar vulnerabilidades.

Um Cookie também é uma tupla chave/valor, e podemos transferir um ou mais Cookies do Servidor HTTP ao Web Browser, e receber seus valores de volta. Estas informações são trafegadas em chaves específicas dentro do Header da requisição HTTP. Para tornar mais fácil a manutenção destas informações, e você não precisar buscar as informações de Cookies e fazer a interpretação delas dentro da sua aplicação, o Protheus como Web Server faz este trabalho, e permite ler as informações de Cookies recebidos, e gravar novos cookies ou redefinir os valores dos Cookies a serem enviados como retorno ao Web Browse.

Alias Virtual HTTPCOOKIES

De forma similar aos demais alias virtuais, podemos recuperar valores de Cookies previamente retornados ao Web Browse, e e criar novas chaves com novos valores a serem armazenados no Web Browser, bem como trocar valores de cookies já existentes — desde que eles tenha sido criados pela nossa aplicação, e pertençam pelo menos ao mesmo host ou domínio — veja sobre escopo de Cookies no link “Cookies HTTP“.

No exemplo de requisição HTTP mostrado no post anterior (Protheus e AdvPL ASP – Parte 04), um dos campos do Header HTTP continha a seguinte informação:

Cookie: SESSIONID=41a79408567715479073622c71988001

Este Cookie foi criado internamente pelo Web Server do Protheus, para identificar a seção atual do usuário. Por isso ele foi recebido. Na primeira requisição que este usuário fez para o Web Server, após iniciar o Web Browser, este Cookie não existia, então o Web Server Protheus sabe que trata-se de uma nova seção, e cria um identificador para aquela seção, e retorna ele no header de retorno (HTTPHEADOUT) do HTTP.

Set-cookie: SESSIONID=41a79408567715479073622c71988001

Utilizando o alias virtual HTTPCOOKIES, eu poderia ler diretamente este cookie sem precisar fazer o tratamento do valor de HTTPHEADIN->COOKIE, que poderia inclusive conter mais de um Cookie. Por exemplo, para ler o cookie SESSIONID, eu utilizaria HTTPCOOKIES->SESSIONID. O Cookie SESSIONID é de uso interno do mecanismo de controle de sessões de usuário — inclusive das variáveis de seção ( HTTPSESSION ). Logo, não devemos mexer neste valor.

Vale lembrar que a soma de chaves e valores de Cookies têm capacidade limitada de armazenamento — eu pessoalmente não usaria nada maior que 256 bytes — lembrando que a transmissão destes valores em cada requisição podem acabar interferindo no peso e desempenho das requisições.

Propriedades estendidas dos Alias Virtuais

Agora que nós já vimos todos os alias virtuais disponíveis para o AdvPL ASP, vamos ver algumas propriedades estendidas de cada um deles, que podem ser muito úteis em várias situações.

HTTPGET->AGETS

O alias virtual HTTPGET possui um campo reservado, chamado “AGETS”. Trata-se de um array de strings, contendo em cada elemento o nome de um identificador de parâmetro informado na URL da requisição. Este campo montado dinamicamente pelo servidor Protheus antes de alocar um processo (Working Thread) para processar uma requisição de link .apw

Por exemplo, vejamos a URL abaixo:

http://localhost/info.apw?a=1&b=2&c

Ao processar esta requisição em AdvPL ASP, podemos recuperar o valor de cada um dos parâmetros informados no AdvPL, usando o alias virtual HTTPGET, desde que saibamos os nomes dos parâmetros, usando por exemplo:

cValorA := HTTPGET->A
cValorB := HTTPGET->B

Caso eu queira saber quais foram os identificadores usados na URL, eu posso consultar o campo HTTPGET->AGETS, por exemplo:

For nI := 1 to len(HTTPGET->AGETS)
  conout("GET "+cValToChar(nI)+" Identificador "+HTTPGET->AGETS[nI]
Next
// o resultado esperado no log de console do 
// servidor de aplicação é:
// GET 1 Identificador a
// GET 2 Identificador b
// GET 3 Identificador c

Reparem que “c” foi um identificador passado na URL, porém ele não teve valor atribuído. Agora, existe uma forma de recuperarmos os conteúdos destes identificadores, a partir dos nomes, usando macro-execução:

For nI := 1 to len(HTTPGET->AGETS)
  cIdent := HTTPGET->AGETS[nI]
  conout("GET "+cValToChar(nI)+" Id "+ cIdent + ;
  " Valor "+cValToChar( &("HTTPGET->"+cIdent) ) )
Next
// o resultado esperado no log de console do 
// servidor de aplicação é:
// GET 1 Id a Valor 1
// GET 2 Id b Valor 2
// GET 3 Id c Valor

HTTPPOST->APOST

Para o alias virtual HTTPPOST, existe o campo reservado “APOST“, com o mesmo propósito e funcionamento do AGETS. A diferença é que somente são informados valores nestes campos caso a requisição HTTP seja enviado o comando POST, o tipo de conteúdo da requisição seja “application/x-www-form-urlencoded“, e o corpo da requisição contenha uma ou mais tuplas chave/valor codificadas.

A mesma técnica utilizada para recuperar os valores associados aos identificadores recebidos em AGETS pelo alias virtual HTTPGET pode ser utilizada para recuperar os valores recebidos em APOST pelo alias virtual HTTPPOST.

HTTPHEADIN->AHEADERS

Para o alias virtual HTTPHEADIN, existe o campo reservado AHEADERS, criado com o propósito de tornar possível receber todas as linhas do cabeçalho da requisição HTTP vindas do Web Browse ou do Web Client que fez a solicitação. No caso, cada linha do cabeçalho HTTP, formado por uma tupla chave/valor, é retornada como um elemento deste array — e não apenas o nome do identificador, como é retornado por AGETS (do Alias HTTPGET) ou APOST (do alias HTTPPOST). Por exemplo:

<pre>
<% For nI := 1 to len(HTTPHEADIN->AHEADERS) %>
<%= HTTPHEADIN->AHEADERS[nI] %>
<% Next %>
</pre>

O trecho acima, dentro de um fonte APH, retornaria ao Browse em texto pré-formatado (ou fonte de tamanho fixa) todas as linhas do Header HTTP recebido pelo Web Server do Protheus para a requisição atual.

HTTPHEADIN->COMMAND

A primeira linha do HTTP Header enviada por um Web Browser ou Web Client do protocolo HTTP contém um comando — normalmente GET ou POST.  Para saber qual foi o comando recebido, podemos usar o campo reservado “COMMAND”.

HTTPHEADIN->MAIN

Ao receber uma requisição de link .apw, para processamento de AdvPL ASP, usamos o campo reservado “main”, do alias virtual HTTPHEADIN, alimentado apenas com o nome da página que foi requisitada, desconsiderando URL, domínio, path e parâmetros. Por exemplo, ao solicitar http://seuhostouip/suapasta/meulink.apw?a=1&b=2, o resultado de HTTPHEADIN->MAIN será apenas “meulink

HTTPHEADIN->CMDPARMS

De forma similar ao campo reservado MAIN, o campo CMDPARMS recebe o nome do link .apw chamado, e os eventuais parâmetros recebidos na URL, no formato de uma única string, onde apenas é removida a extensão “.apw” da requisição. Por exemplo, ao solicitar http://seuhostouip/suapasta/meulink.apw?a=1&b=2, o resultado de HTTPHEADIN->CMDPARMS será apenas “meulink?a=1&b=2

HTTPCOOKIES->ACOOKIES

Este campo reservado do alias virtual HTTPCOOKIES funciona exatamente igual ao AGETS e APOST. Ele traz apenas os nomes dos Cookies enviado pelo Cliente Web ao Web Server Protheus em uma requisição de AdvPL ASP.

<pre>
<% For nI := 1 to len(HTTPCOOKIES->ACOOKIES) %>
<%= HTTPCOOKIES->ACOOKIES[nI] %>
<% Next %>
</pre>

O trecho acima, dentro de um fonte APH, mostrará todos os nomes dos identificadores de Cookies recebidos pela requisição atual.

HTTPSESSION->SESSIONID

Funciona de forma similar ao HTTPCOOKIES->SESSIONID, porém com uma diferença: Na primeira requisição recebida pelo AdvPL ASP de uma nova seção do Web Browser, o identificador do SESSIONID vêm em branco, pois o Cookie identificador de seção ainda não foi retornado ao Browse. Já o HTTPSESSION->SESSIONID já vem preenchido com o identificador criado para esta seção antes mesmo dele ser retornado ao browse.

Exemplo COMPLETO

Vamos ver o que a podemos recuperar de uma requisição HTTP vinda de um Web Browse em AdvPL ASP, agora em um único exemplo? Primeiro, criamos um desvio na função U_ASPConn(), para executar a função H_ASPINFO() caso seja informado no browse a chamada para o link “aspinfo.apw“.

case cAspPage == 'aspinfo'
  cReturn := H_ASPINFO()

Agora, criamos o arquivo “aspinfo.aph“, com o seguinte conteúdo:

<html><body>
<pre>
HTTP HEADER INFO
<hr>
<% For nI := 1 to len(HTTPHEADIN->AHEADERS) %>
<%= HTTPHEADIN->AHEADERS[nI] %>
<% Next %>

Command .....: <%=HTTPHEADIN->COMMAND%>
Main ........: <%=HTTPHEADIN->MAIN%>
CmdParms ....: <%=HTTPHEADIN->CMDPARMS%>
Remote Addr .: <%=HTTPHEADIN->REMOTE_ADDR%>
Remote Port .: <%=HTTPHEADIN->REMOTE_PORT%>

<% If len(HTTPCOOKIES->ACOOKIES) > 0 %>
COOKIES
<hr>
<% For nI := 1 to len(HTTPCOOKIES->ACOOKIES) %>
<% cVar := HTTPCOOKIES->ACOOKIES[nI] %>
<%= cVar + " = [" + &("HTTPCOOKIES->"+cVar) + "]" %>
<% Next %>
<% Endif %>

<% If len(HTTPGET->AGETS) > 0 %>
GET PARAMS
<hr>
<% For nI := 1 to len(HTTPGET->AGETS) %>
<% cVar := HTTPGET->AGETS[nI] %>
<%= cVar + " = [" + &("HTTPGET->"+cVar) + "]" %>
<% Next %>
<% EndIf %>

<% If len(HTTPPOST->APOST) > 0 %> 
POST PARAMS
<hr>
<% For nI := 1 to len(HTTPPOST->APOST) %>
<% cVar := HTTPPOST->APOST[nI] %>
<%= cVar + " = [" + &("HTTPPOST->"+cVar) + "]" %>
<% Next %>
<% EndIf %>

REQUEST DETAILS
<hr>
HttpOtherContent() ......: <%=HttpOtherContent()%>
HttpRCTType() ...........: <%=HttpRCTType()%>
HttpRCTDisp() ...........: <%=HttpRCTDisp()%>
HttpRCTLen() ............: <%=HttpRCTLen()%>
</pre>
</body></html>

Agora vamos ver a mágica funcionando. Com tudo compilado e o Protheus no ar, entramos com a seguinte URL: http://localhost/aspinfo.apw?a=1Veja abaixo o resultado esperado no Web Browse:

HTTP HEADER INFO

GET /aspinfo.apw?a=1 HTTP/1.1
Host: localhost
Connection: keep-alive
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.110 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8
Accept-Encoding: gzip, deflate, br
Accept-Language: pt-BR,pt;q=0.9,en-US;q=0.8,en;q=0.7,es;q=0.6
Cookie: SESSIONID=72b298eea3eed9544ad95459e833e7c2

Command .....: GET
Main ........: aspinfo
CmdParms ....: aspinfo?a=1
Remote Addr .: 127.0.0.1
Remote Port .: 52764

COOKIES

SESSIONID = [f62f4ac8afc9f1b3456faafc93551bc5]

GET PARAMS

A = [1]

REQUEST DETAILS

HttpOtherContent() ......: 
HttpRCTType() ...........: 
HttpRCTDisp() ...........: 
HttpRCTLen() ............: -1

E se fosse um POST ?

Claro, vamos ver o que eu receberia em um post. Aproveitando o exemplo de um post anterior, vamos editar o arquivo formpost.aph, e trocar o ACTION do formulário de “/postinfo.apw” para “/aspinfo,apw”, e ver  o que acontece.

<html><body>
<p>Formulário de POST</p>
<form action="/aspinfo.apw" method="post">
First name:<br>
<input type="text" name="firstname"><br>
Last name:<br>
<input type="text" name="lastname">
<hr>
<input type="submit" value="Enviar">
</form>
</body></html>

Agora, vamos abrir a URL http://localhost/formpost.apw, e no caso, eu vou digitar meu nome e sobrenome nos campos:

Web formpost

Após clicar no botão ENVIAR, o retorno esperado no Browse deve ser algo assim:

HTTP HEADER INFO

POST /aspinfo.apw HTTP/1.1
Host: localhost
Connection: keep-alive
Content-Length: 34
Cache-Control: max-age=0
Origin: http://localhost
Upgrade-Insecure-Requests: 1
Content-Type: application/x-www-form-urlencoded
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.110 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8
Referer: http://localhost/formpost.apw
Accept-Encoding: gzip, deflate, br
Accept-Language: pt-BR,pt;q=0.9,en-US;q=0.8,en;q=0.7,es;q=0.6
Cookie: SESSIONID=fe5ab7f15a1b9788fd945bf14581af82

Command .....: POST
Main ........: ASPINFO
CmdParms ....: ASPINFO
Remote Addr .: 127.0.0.1
Remote Port .: 53500

COOKIES

SESSIONID = [f9d8c4a25dc307251bf05300f59bf3e4]

POST PARAMS

FIRSTNAME = [Júlio]
LASTNAME = [Wittwer]

REQUEST DETAILS

HttpOtherContent() ......: 
HttpRCTType() ...........: application/x-www-form-urlencoded
HttpRCTDisp() ...........: 
HttpRCTLen() ............: 34

Conclusão

Com este post, cobrimos o básico do AdvPL ASP. Nos próximos posts deste assunto, vamos abordar algumas capacidades de retorno diferenciado da interface HTTP, e como utilizá-las quando necessário. Afinal, podemos retornar ao Web Browser ou ao Client HTTP utilizado muito mais do que apenas HTML 😀

Agradeço novamente a audiência, e desejo a todos TERABYTES DE SUCESSO !!!! 

Referências

 

 

Um comentário sobre “Protheus e AdvPL ASP – Parte 05

Deixe um comentário

Preencha os seus dados abaixo ou clique em um ícone para log in:

Logotipo do WordPress.com

Você está comentando utilizando sua conta WordPress.com. Sair /  Alterar )

Foto do Google

Você está comentando utilizando sua conta Google. Sair /  Alterar )

Imagem do Twitter

Você está comentando utilizando sua conta Twitter. Sair /  Alterar )

Foto do Facebook

Você está comentando utilizando sua conta Facebook. Sair /  Alterar )

Conectando a %s