Sie sind auf Seite 1von 20

UNIVERSIDADE NOVA DE LISBOA

Faculdade de Cincias e Tecnologia


Departamento de Engenharia Electrotcnica

REDES INTEGRADAS DE TELECOMUNICAES II 2005 / 2006

Licenciatura em Engenharia Electrotcnica e de Computadores 4 ano 8 semestre

1 Trabalho prtico: Servidor HTTP com JavaCGI

http://tele1.dee.fct.unl.pt

Luis Bernardo

NDICE
1. OBJECTIVOS ...................................................................................... 2 2. COMPLEMENTOS SOBRE HTTP ........................................................... 2 2.1 O protocolo HTTP......................................................... 2 2.2 Cookies ......................................................................... 4 2.3 Formulrios e CGI (Common Gateway Interface)......... 5 2.4 Controlo de caching ...................................................... 5 3. COMPLEMENTOS SOBRE JAVA ............................................................. 6 3.1. IPv6 ............................................................................. 6 3.2 Sockets TCP................................................................. 7 3.2.1. A classe ServerSocket 3.2.2. A classe Socket 3.2.3. Comunicao em sockets TCP 3.2.4. Exemplo de aplicao - TinyFileServ 7 8 9 10

3.3 Strings .......................................................................... 11 3.3.1. Separao em componentes 3.3.2. Datas compatveis com o protocolo HTTP 3.3.3. URLs 11 11 12

3.4 Ficheiros ....................................................................... 13 3.5 Estruturas de dados adicionais..................................... 13 3.6 Carregamento de classes em tempo real ..................... 14 4. ESPECIFICAES ............................................................................... 15 4.1 Especificao detalhada............................................... 15 4.2 Interface de programao para objectos JavaCGI ....... 16 4.3 Testes........................................................................... 17 4.4 Desenvolvimento do trabalho ....................................... 17 BIBLIOGRAFIA ........................................................................................ 18 DATAS LIMITE ........................................................................................ 18
1

1. OBJECTIVOS
Familiarizao com os protocolos Web e com a programao de aplicaes em Java baseadas em sockets TCP. O trabalho consiste no
desenvolvimento de um servidor Web dual-stack multi-tarefa que suporta pginas dinmicas baseadas em formulrios (forms) e CGI utilizando classes Java. Este servidor deve realizar os comandos GET e POST, e um subconjunto limitado das funcionalidades do protocolo HTTP, permitindo a sua realizao num nmero reduzido de horas. Pretende-se que o procurador Web satisfaa um conjunto de requisitos: Funcione tanto para IPv6 como IPv4; Seja compatvel com HTTP 1.0 e HTTP 1.1; Controle o nmero de segundos que mantm uma ligao aberta (em HTTP 1.1); Carregue dinamicamente os objectos JavaCGI quando invocados; Interprete os cabealhos HTTP, passando os cabealhos, e os cookies para os objectos JavaCGI; Interprete os campos dos formulrios, enviando-os para os objectos JavaCGI. Este trabalho complementa a aprendizagem sobre Java realizada no primeiro trabalho de RIT1, acrescentando novos conhecimentos introduzidos na terceira seco deste documento. Antes, na segunda seco apresentado um resumo das caractersticas do protocolo HTTP relevantes para este trabalho. Na quarta seco apresentada a especificao completa do servidor. tambm apresentada uma descrio de excertos de software que so fornecidos, para facilitar a realizao do trabalho.

2. COMPLEMENTOS SOBRE HTTP


Esta seco introduz os aspectos mais relevantes do protocolo HTTP (HyperText Transfer Protocol), para a realizao do trabalho. Recomenda-se que os alunos consultem mais documentao sobre o protocolo HTTP, no livro terico recomendado e em [1].

2.1 O protocolo HTTP


O protocolo HTTP define uma interaco do tipo pedido-resposta entre um cliente e um servidor, onde as mensagens trocadas contm texto legvel. Existe duas verses do protocolo: HTTP 1.0 [2] e HTTP 1.1 [3]. A mensagem de pedido, do cliente para o servidor tem a seguinte estrutura (sp = espao ; cr lf = mudana de linha). O URL corresponde ao nome de um ficheiro local (num servidor):

Mtodo

sp

URL

sp : :

Verso valor valor cr cr

cr lf

lf

Pedido Linhas cabealho

Nome campo cabealho Nome campo cabealho cr lf

lf

Corpo da mensagem

Os mtodos GET e POST tm uma estrutura semelhante. Um pedido pode incluir diversas linhas de cabealhos opcionais, que definem a data de acesso ao servidor (Date), o nome do servidor acedido (Host) (obrigatrio quando o servidor HTTP suporta vrias mquinas virtuais), o tipo de browser e sistema operativo usado (User-Agent), os formatos de dados suportados (Accept), a lngua pretendida (Accept-Language), se o ficheiro foi modificado desde o ltimo acesso (If-Modified-Since e If-None-Match), para HTTP1.1 a indicao se pretende manter a ligao aberta (Connection) e durante quanto tempo (Keep-Alive), o tipo dos dados no corpo da mensagem (Content-Type), o nmero de bytes da mensagem (Content-Length), dados de sesso (Cookie ou Cookie2), etc. Depois, separando o cabealho de um corpo de mensagem opcional, existe uma linha em branco. Os valores dos campos do formulrio geralmente vm nos dados. Um exemplo de pedido (GET) a um servidor ser:
GET /page.html HTTP/1.1 Connection: close User-agent: Mozilla/4.0 Accept-language:pt

As mensagens de resposta tm uma estrutura semelhante:


Verso sp Cdigo estado : : sp Frase cr lf

Pedido Linhas cabealho

Nome campo cabealho Nome campo cabealho cr lf

valor valor

cr lf cr lf

Corpo da mensagem O campo mais importante da resposta o cdigo de estado, que define o que se passou com o pedido. Os cdigos de estado devolvidos podem ser: Cdigo 1xx 2xx 3xx 4xx 5xx Tipo Informao Sucesso Redireco Erro do cliente Erro do servidor Exemplo de razes Rec. pedido, continua processamento Aco terminada com sucesso Necessrias mais aces para completar Pedido errado, no pode ser executado Servidor falhou com pedido vlido

Alguns exemplos de cdigos de estado teis para o trabalho so: 200 OK: Sucesso - informao retornada no corpo da mensagem 301 Moved Permanently: Moveu-se para URL contido no campo de cabealho 'Location:' 304 Not Modified: Ficheiro no foi modificado 400 Bad Request: Pedido no entendido pelo servidor 404 Not found: O ficheiro pedido no existe ou no pode ser acedido 501 Not implemented: Pedido no suportado pelo servidor As respostas incluem alguns cabealhos semelhantes aos pedidos (Content-Type, ContentLength, Connection, Date, etc.), acrescentando outros opcionais especficos, como a indicao da ltima modificao do ficheiro (Last-Modified), do valor de hash do ficheiro (ETag), a definio de um estado no cliente (Set-Cookie ou Set-Cookie2), e o controlo de cache (CacheControl em HTTP 1.1 ou Pragma em HTTP 1.0). Observe-se que o cabealho Content-Type

obrigatrio sempre se devolverem dados, indicando o tipo de dados MIME 1 , de forma ao browser saber como interpretar os dados. Ficheiros HTML so codificados no formato text/html, enquanto ficheiros de imagens podem ser codificados em image/gif ou image/jpeg, podendo para efeitos deste trabalho ser enviados os restantes dados como application/octet-stream. No caso de ficheiros HTML, tambm importante o cabealho Content-Encoding, com o formato de codificao. Recomenda-se que seja SEMPRE usado o formato "ISO-8859-1" em todos os ficheiros de texto no procurador. Um exemplo de uma resposta de um servidor seria:
HTTP/1.1 200 OK Connection: close Date: Sat, 30 Set 2003 12:00:00 GMT Last-Modified: Thu, 28 Set 2003 19:00:00 GMT Server: Demo RIT2 2004/2005 v1.0 Content-Length: 6821 Content-Type: text/html Content-Encoding: iso-8859-1 { dados html }

A principal diferena entre HTTP 1.0 e HTTP 1.1 est no controlo da ligao TCP. No primeiro caso (1.0) a ligao fechada aps cada pedido. No segundo (1.1) podem ser usados os campos de cabealho (Connection e Keep-Alive) no pedido e na resposta para definir se se mantm a ligao TCP aberta e por quanto tempo. Se tanto o pedido como a resposta contiver um campo de cabealho Connection com um valor diferente de close, a ligao TCP no desligada, podendo ser enviados vrios pedidos atravs dessa ligao. Um exemplo de valores um cabealho de resposta a manter a ligao durante 60 segundos seria:
Connection: keep-alive Keep-Alive: 60

2.2 Cookies
Para se poder ter estados associado a uma ligao HTTP (que por desenho no tem estado), foram definidos dois campos de cabealho adicionais numa norma externa [5] ao HTTP. Sempre que um servidor adiciona um campo Set-Cookie mensagem, o browser memoriza o valor recebido e retorna-o nos pedidos seguintes ao mesmo servidor. A sintaxe deste campo :
Set-Cookie: NAME=VALUE; expires=DATE; path=PATH; domain=DOMAIN_NAME; secure

NAME=VALUE define o nome e o valor do cookie. o nico campo obrigatrio, podendose usa a forma simplificada Set-Cookie: VALUE para um nome vazio. expires=DATE define a validade do cookie. Se no for definido, o cookie desaparece quando se fecha o browser. Pode eliminar-se um cookie, enviando uma data anterior data actual. domain=DOMAIN_NAME Define o nome do servidor. O mesmo servidor Web poder suportar vrios servidores virtuais, fazendo-se a distino pelo valor do campo de cabealho Host. Se no for definido, o cookie enviado baseado no endereo IP.

Ver pgina 599 de [4] com lista de tipos 4

path=PATH documento raiz a partir da qual todos os documento levam o mesmo cookie. Se no for definido, o cookie apenas enviado para a pgina pedida. secure se seleccionado, o cookie apenas enviado para ligaes seguras. Se um cliente enviar o campo:
Set-Cookie: CUSTOMER=WILE_E_COYOTE; path=/; expires=Wednesday, 09-Nov99 23:12:40 GMT

Recebe nos pedidos seguintes para todos os documentos abaixo de /:


Cookie: CUSTOMER=WILE_E_COYOTE

O servidor pode definir vrios cookies em campos de cabealho Set-cookie separados, que so devolvidos concatenados (separados por ;) num nico campo de cabealho Cookie nos pedidos futuros.

2.3 Formulrios e CGI (Common Gateway Interface)


Os formulrios (forms) apareceram com o HTML 2.0 [6] e suportam a definio de campos de entrada de dados, delimitados entre as etiquetas <form> e </form>. Cada campo de um formulrio identificado por um nome (name) e tem associado um tipo (type) que pertence a um conjunto predefinido de tipos (e.g. Checkboxes, Radio Buttons, Text boxes, Submit buttons, etc.), e por um valor inicial (value). Por exemplo:
<form ACTION=http://mariel.inesc.pt/cgi-bin/finger method=POST> Name <input type="text" name =Finger size=40></form>

Quando se invoca o mtodo POST atravs de um "submit button", ou indirectamente atravs de um GET com um campo "?xxx" num URL, os valores so enviados para o servidor num formato compacto, que concatena todos os campos do formulrio numa string, delimitados pelo caracter '&'. Cada campo codificado como "nome=valor", onde todos os espaos em branco so substitudos pelo carcter '+', e os caracteres reservados so substitudos pelo valor numrico correspondente em hexadecimal no formato "%aa" (no caso do Internet Explorer constata-se que muitas vezes no segue a norma e substitui os espaos por "%A0"). Por exemplo, o seguinte conjunto de campos (representados na forma nome=valor)
star = Eastwood cert = 15 movie = Pale Rider

seria codificado na cadeia de caracteres "star=Eastwood&cert=15&movie=Pale+Rider". Vulgarmente, os dados enviados atravs de um POST so processados num script Perl (abordagem vulgarmente designada por CGI (Common Gateway Interface)), num script PHP, em objectos Java (com servlets ou JSP), ou objectos ASP. Para evitar a tentao de usar o muito cdigo existente na Internet, neste trabalho define-se mais um formato de interface do servidor Web com um objecto externo para tratar o mtodo POST, a meio caminho entre CGI e servlets. Pode-se encontrar mais informao sobre a utilizao de forms nas pginas 634-638 do livro recomendado na disciplina [4], ou em vrias pginas tutoriais existentes na Internet (e.g. [7]).

2.4 Controlo de caching


Quando um browser recebe um ficheiro, costuma guard-lo numa memria local, designada de cache. Para que o ficheiro possa ser guardado, ele no dever ter campos de autenticao, ou
5

cookies. O HTTP define vrios mtodos para controlar se o ficheiro continua actual. Os mais comuns usam os campos de cabealho If-Modified-Since e "If-None-Match". No primeiro caso, no segundo pedido, acrescenta-se o cabealho com a data da ltima modificao; no segundo caso o cabealho com a assinatura digital do ficheiro (recebida no campo "ETag"). Caso o ficheiro seja actual deve-se responder com o cdigo 304. Caso contrrio, deve-se ignorar o campo de cabealho, e devolver o novo ficheiro.
PEDIDO 1: GET /somedir/page.html HTTP/1.0 RESPOSTA 1: HTTP/1.0 200 OK Last-Modified: Thu, 23 Oct 2002 12:00:00 GMT ETag:"a4137-7ff-42068cd3" PEDIDO 2: GET /somedir/page.html HTTP/1.0 If-Modified-Since: Thu, 23 Oct 2002 12:00:00 GMT If-None-Match: "a4137-7ff-42068cd3" RESPOSTA 2: HTTP/1.0 304 Not Modified Date: Thu, 23 Oct 2002 12:35:00 GMT

Outros mtodos consistem na utilizao de campos de controlo de caching. Em HTTP 1.0 pode ser retornado o campo de cabealho Pragma: no-cache tanto nos pedidos (no usar como resposta valores em cache) como nas respostas (no guardar em cache). Em HTTP 1.1 deve ser usado o campo de cabealho Cache-control que pode ter um subconjunto de vrios valores possveis. O valor "no-cache" tem o mesmo significado que anteriormente. O valor "nostore" no pedido ou resposta significa que a resposta no pode nunca ser guardada em cache. O valor "max-age=n" define o tempo mximo de vida da resposta, ou o tempo mximo que o ficheiro pode estar em cache para ser vlido. O valor "s-maxage=n" numa resposta indica qual validade mxima de um ficheiro num procurador.

3. COMPLEMENTOS SOBRE JAVA


Nesta seco admite-se que os alunos j leram e conhecem o contedo do documento Introduo programao em rede para Java: Desenvolvimento de aplicaes utilizando NetBeans e UDP 2 usado durante um trabalho da disciplina precedente. Este trabalho vai ser desenvolvido no mesmo ambiente (NetBeans), que distribudo gratuitamente pela Sun Microsystems juntamente com o ambiente Java.

3.1. IPv6
O protocolo IPv6 suportado de uma forma transparente na linguagem Java, a partir da verso Java 1.4. A classe InetAddress tanto permite lidar com endereos IPv4 como IPv6. Esta classe tem como subclasses Inet4Address e Inet6Address, que suportam respectivamente as funes especficas relativas aos endereos IPv4 e IPv6. Esta arquitectura permite suportar endereos IPv6 de uma forma transparente nas restantes classes do pacote java.net, uma vez que
2

Disponvel em http://tele1.dee.fct.unl.pt/rit1_2005_2006/lab/enunc_rit1_java_20052006.pdf 6

as restantes funes usam parmetros da classe InetAddress nos argumentos e nas variveis dos objectos das classes. possvel obter o endereo local da mquina IPv4 ou IPv6 usando a funo da classe getLocalHost:
try { InetAddress addr = InetAddress.getLocalHost(); } catch (UnknownHostException e) { // tratar excepo }

O mtodo getHostAddress permite obter o endereo em formato string. O nome associado ao endereo pode ser obtido com o mtodo getHostName.

3.2 Sockets TCP


Em Java, a interface para sockets TCP realizada atravs de duas classes: ServerSocket e Socket.

3.2.1. A classe ServerSocket


A classe ServerSocket define um objecto servidor que pode receber e manter vrias ligaes abertas. Quando se cria um objecto, define-se o porto onde vai escutar. O mtodo accept() bloqueia o objecto at que seja recebida uma ligao ao porto, criando um objecto da classe Socket que permite comunicar com o cliente. Nova ligao

Aplicao Servidora
ServerSocket

Aplicao Cliente
Socket

Socket

Socket

Socket

Aplicao Cliente
Socket

Os construtores da classe ServerSocket permitem definir o porto, o nmero de novas ligaes pendentes que so aceites pelo objecto e o endereo IP (a interface) a que se faz a associao. Em Java 1.4 surgiu um quarto construtor sem parmetros, que no inicializa o porto, permitindo usar a funo setReuseAddress(), antes de definir o porto com a funo bind().

// Public Constructors public ServerSocket(int port) throws IOException; public ServerSocket(int port, int backlog) throws IOException; public ServerSocket(int port, int backlog, InetAddress bindAddr) throws IOException; public ServerSocket() throws IOException; // apenas para Java 1.4

As duas funes principais permitem receber ligaes e terminar o servidor.


public Socket accept() throws IOException; public void close() throws IOException;

Outras funes permitem ter acesso s variveis do objecto:


public InetAddress getInetAddress(); public int getLocalPort(); public synchronized int getSoTimeout() throws IOException; public synchronized void setSoTimeout(int timeout) throws SocketException;

Para permitir comunicar com os clientes e aceitar novas ligaes em paralelo comum usar mltiplas tarefas (threads) para lidar com cada ligao.

3.2.2. A classe Socket


A classe Socket define um objecto de intercomunicao em modo feixe. Pode ser criado atravs de um construtor ou a partir da operao accept. O construtor permite programar clientes: especifica-se o endereo IP e porto a que se pretende ligar, e o construtor estabelece a ligao.
public Socket(String host, int port) throws UnknownHostException, IOException; public Socket(InetAddress address, int port) throws IOException; public Socket(String host, int port, InetAddress localAddr, int localPort) throws IOException; public Socket(InetAddress address, int port, InetAddress localAddr, int localPort) throws IOException;

As operaes de escrita e leitura do socket so realizadas atravs de objectos do pacote java.io (InputStream e OutputStream), descritos na prxima seco, retornados por duas funes da classe. Existem ainda funes para fechar o socket e para obter informaes sobre a identidade da ligao.
public public public public public public public public public InputStream getInputStream() throws IOException; OutputStream getOutputStream() throws IOException; synchronized void close() throws IOException; InetAddress getInetAddress(); InetAddress getLocalAddress(); int getLocalPort(); int getPort(); isConnected(); // Java 1.4 isClosed(); // Java 1.4

Vrias operaes de configurao dos parmetros do protocolo TCP podem ser realizadas atravs de mtodos desta classe. As funes getReceiveBufferSize, setReceiveBufferSize, getSendBufferSize e setSendBufferSize permitem modificar a dimenso dos buffers usados no protocolo TCP. As funes getTCPNoDelay e setTCPNoDelay controlam a utilizao do algoritmo de Nagle (false = desligado). As funes getSoLinger e setSoLinger controlam o que acontece quando se fecha a ligao: se est ligada o valor define o nmero de segundos que se
8

espera at tentar enviar o resto dos dados que esto no buffer TCP e ainda no foram enviados. Caso esteja activo, pode originar perda de dados no detectvel pela aplicao.
public int getReceiveBufferSize() throws SocketException; public synchronized void setReceiveBufferSize(int size) throws SocketException; public int getSendBufferSize() throws SocketException; // 1.4 public synchronized void setSendBufferSize(int size) throws SocketException; // 1.4 public boolean getTcpNoDelay() throws SocketException; public void setTcpNoDelay(boolean on) throws SocketException; public int getSoLinger() throws SocketException; public void setSoLinger(boolean on, int val) throws SocketException; public synchronized int getSoTimeout() throws SocketException; public synchronized void setSoTimeout (int timeout) throws SocketException;

As funes getSoTimeout e setSoTimeout permitem configurar o tempo mximo que uma operao de leitura pode ficar bloqueada, antes de ser cancelada. Caso o tempo expire gerada uma excepo SocketTimeoutException. Estas funes tambm existem para as classes ServerSocket e DatagramSocket.

3.2.3. Comunicao em sockets TCP


Os objectos da classe Socket oferecem mtodos para obter um objecto da classe InputStream (getInputStream) para ler do socket, e para obter um objecto da classe OutputStream (getOutputStream). No entanto, estas classes apenas suportam a escrita de arrays de bytes. Assim, comum usar outras classes do pacote java.io para envolver estas classes base, obtendo-se uma maior flexibilidade: Para ler strings a partir de um socket possvel trabalhar com: A classe InputStreamReader processa a cadeia de bytes interpretando-a como uma sequncia caracteres (convertendo o formato de carcter). A classe BufferedReader armazena os caracteres recebidos a partir de um feixe do tipo InputStreamReader, suportando o mtodo readLine() para esperar pela recepo de uma linha completa. Para escrever strings num socket possvel trabalhar com: A classe OutputStreamWriter processa a cadeia de caracteres e codifica-a para uma sequncia de bytes. A classe PrintWriter suporta os mtodos de escrita de strings e de variveis de outros formatos (print e println) para um feixe do tipo OutputStreamWriter. A classe PrintStream suporta os mtodos de escrita de strings e de byte [] para um feixe do tipo OutputStream. Caso se pretendesse enviar objectos num formato binrio (no legvel), dever-se-ia usar as classes DataInputStream e DataOutputStream. Um exemplo de utilizao destas classes seria o apresentado em seguida:
try { // soc representa uma varivel do tipo Socket inicializada // Cria feixe de leitura InputStream ins = soc.getInputStream( ); BufferedReader in = new BufferedReader( new InputStreamReader(ins, "8859_1" )); // Tipo de caracter // Cria feixe de escrita OutputStream out = soc.getOutputStream( ); PrintStream pout = new PrintStream(out);

// Em alternativa poder-se-ia usar PrintWriter: // PrintWriter pout = new PrintWriter( // new OutputStreamWriter(out, "8859_1"), true); // L linha e ecoa-a para a sada String in_string= in.readln(); pout.writeln("Recebi: "+ in_string); } catch (IOException e ) { ... }

3.2.4. Exemplo de aplicao - TinyFileServ


No exemplo seguinte apresentado um servidor de ficheiros parcialmente compatvel com o protocolo HTTP (utilizvel por browsers), que recebe o nome do ficheiro no formato (* nomecompleto *) e devolve o contedo do ficheiro, fechando a ligao aps o envio do ltimo caracter do ficheiro. O servidor recebe como argumentos da linha de comando o nmero de porto a partir da linha de comando e o directrio raiz correspondente directoria "/" (e.g. java TinyFileServ 20000 /home/rit2/www). Para cada nova ligao, o servidor lana uma tarefa que envia o ficheiro pedido e termina aps o envio do ficheiro. O servidor compatvel com um browser: l o segundo campo do pedido (e.g. GET / HTTP/1.1). No enviado o cdigo de resposta, mas os browsers mais vulgares (IE, Firefox, etc.) sabem interpretar o ficheiro recebido a partir dos primeiros caracteres e do nome do ficheiro. Este exemplo usa algumas classes descritas nas prximas seces deste captulo.
//file: TinyFileServd.java import java.net.*; import java.io.*; import java.util.*; public class TinyFileServd { public static void main( String argv[] ) throws IOException { ServerSocket ss = new ServerSocket( Integer.parseInt(argv.length>0 ? argv[0] : "20000")); while ( true ) new TinyFileConnection(ss.accept(), (argv.length>1 ? argv[1] : "")).start( ); } } // end of class TinyFileServd class TinyFileConnection extends Thread { private Socket client; private String root; TinyFileConnection ( Socket client, String root ) throws SocketException { this.client = client; this.root= root; setPriority( NORM_PRIORITY + 1 ); // Higher the thread priority } public void run( ) { try { BufferedReader in = new BufferedReader( new InputStreamReader(client.getInputStream( ), "8859_1" )); OutputStream out = client.getOutputStream( ); PrintStream pout = new PrintStream(out, false, "8859_1"); String request = in.readLine( ); // Reads the first line System.out.println( "Request: "+request ); StringTokenizer st= new StringTokenizer (request); if (st.countTokens() != 3) return; // Invalid request String code= st.nextToken(); // USES HTTP syntax String file= st.nextToken(); // for requesting files String ver= st.nextToken(); String filename= root+file+(file.equals("/")?"index.htm":""); System.out.println("Filename= "+filename); FileInputStream fis = new FileInputStream ( filename ); byte [] data = new byte [fis.available()]; // Fails for large files fis.read( data ); // Read from file

10

out.write( data ); out.flush( ); fis.close(); client.close( );

// Write to socket // Flush socket buffer

} catch ( FileNotFoundException e ) { System.out.println( "File not found" ); } catch ( IOException e ) { System.out.println( "I/O error " + e ); } } } // end of class TinyFileConnection

3.3 Strings
Uma vez que o protocolo HTTP baseado em strings, para realizar o servidor web vai ser necessrio interpretar comandos e gerar respostas em formato ASCII. Nesta seco so apresentadas algumas das classes que podem ser usadas para desempenhar estas tarefas.

3.3.1. Separao em componentes


Um dos aspectos essenciais a separao de uma string em componentes fundamentais. As classes String e StringBuffer oferecem o mtodo substring para seleccionar uma parte da string:
String a= "Java is great"; String b= a.substring(5); String c= a.substring(0, 4); // b is the string "is great" // c is the string "Java"

O mtodo trim() remove os espaos e tabulaes antes e depois da string. A comparao de strings pode ser feita com os mtodos equals ou equalsIgnoreCase. A linguagem Java oferece a classe StringTokenizer para decompor uma string em substrings separadas por espaos ou outros separadores. O mtodo nextToken() permite percorrer todos os componentes, enquanto os mtodos hasMoreTokens() e countTokens() permitem saber quando se termina. Por exemplo, o cdigo seguinte permite descodificar a primeira linha de um cabealho HTTP nos vrios componentes. O construtor pode ter um segundo parmetro opcional com uma string com a lista de separadores (por omisso tem apenas o espao por separador).
StringTokenizer st = new StringTokenizer( request ); // Pode-se acrescentar um parmetro extra com o separador e.g. ":" if ( (st.countTokens( ) != 3) String rqCode= st.nextToken( ); String rqName= st.nextToken( ); String rqVersion = st.nextToken( ); if (rqCode.equals("GET") || rqCode.equals("POST")) { if ( rqName.startsWith("/") ) rqName = rqName.substring( 1 ); rqName = rqName + "index.htm"; } // Removes first character // Adds index.htm if is a directory if ( rqName.endsWith("/") || rqName.equals("") ) { erro }

3.3.2. Datas compatveis com o protocolo HTTP


O protocolo HTTP define um formato especfico para a escrita de datas:
Thu, 23 Oct 2002 12:00:00 GMT 11

possvel escrever e ler variveis com este formato utilizando uma varivel da classe DateFormat.
DateFormat httpformat= new SimpleDateFormat ("EE, d MMM yyyy HH:mm:ss zz", Locale.UK); httpformat.setTimeZone(TimeZone.getTimeZone("GMT")); // Escrita de datas out.println("A data actual " + httpformat.format(dNow)); // Leitura de datas try { Date dNow= httpformat.parse(str); } catch (ParseException e) { System.out.println("Data invlida: " + e + "\n"); }

possvel comparar datas utilizando o mtodo compareTo de objectos da classe Date. A adio e subtraco de intervalos de tempo a datas tambm so possveis convertendo a data em long utilizando o mtodo getTime. Como o valor conta o nmero de milisegundos desde 1970, basta somar ou subtrair o valor correspondente ao intervalo. Por exemplo, para avanar um dia seria:
Date d= new Date(dNow.getTime() + (long)24*60*60*1000);

Outra alternativa usar a funo add da classe Calendar para realizar a operao:
Calendar now= Calendar.getInstance(); now.add(Calendar.DAY_OF_YEAR, +1); Date d= now.getTime();

3.3.3. URLs
A leitura e validao de URLs podem ser feitas usando a classe java.net.URL. Um URL tem a estrutura seguinte:
<protocolo>://<autoridade><path>?<query>#<fragment>

Esta classe tem vrios construtores que recebem uma string com o URL completo e outro que recebe o url por parmetros. Depois inclui funes que permitem obter os vrios campos do URL:
// Construtores devolvem excepo se url invlido: public URL(String spec) throws MalformedURLException; public URL(String protocol, String host, int port, String file) throws MalformedURLException // Exemplo de mtodos desta classe: URL url= new URL("http://lflb@tele1.dee.fct.unl.pt:8080/servlet/xxx?xpto=ola&xa=xa#2"); url.getProtocol() == "http" url.getAuthority() == " lflb@tele1.dee.fct.unl.pt:8080" url.getUserInfo() == "lflb" url.getPort() == 8080 url.getDefaultPort() == 80 url.getFile() == "/servlet/xxx?xpto=ola&xa=xa" url.getHost() == "tele1.dee.fct.unl.pt" url.getPath() == "/servlet/xxx" url.getQuery() == "xpto=ola&xa=xa" url.getRef() == "2" // "" se omitido // "" se omitido // "" se omitido // null se omitido // null se omitido // "" se omitido // null se omitido // -1 se omitido

12

A biblioteca Java inclui a classe java.net.URLConnection que permite simplificar a criao de ligaes para um URL. Neste trabalho pretende-se realizar essa ligao directamente sobre sockets TCP, para ter um controlo mais fino na comunicao.

3.4 Ficheiros
A classe java.io.File representa um ficheiro ou uma directoria, e define um conjunto de mtodos para os manipular. O construtor recebe o nome completo de um ficheiro, permitindo depois a classe saber se o ficheiro existe, se ficheiro ou directoria, o comprimento do ficheiro, apagar o ficheiro, ou marcar o ficheiro para ser apagado quando o programa termina. Inclui ainda mtodos para criar ficheiros temporrios com nomes nicos.
File f= new File ("/home/pc40/xpto.txt"); // Associa-se a ficheiro long len= f.length(); Date date= new Date(f.lastModified()); if (f.exists()) if (f.isFile()) if (f.canRead()) f.delete(); temp.deleteOnExit(); File.separator // Comprimento do ficheiro // ltima modificao // Se existe // Se ficheiro // Se legvel // Apaga ficheiro // Apaga ficheiro quando a aplicao termina // '/' ou '\\' dependendo do sistema operativo

File temp= File.createTempFile("proxy", ".tmp"); // Cria ficheiro temporrio com nome nico

A leitura a partir de ficheiros de texto geralmente realizada atravs da classe FileInputStream. Recomenda-se que a escrita de ficheiros recebido a partir de servidores Web seja feita atravs da classe BufferedWriter, por esta tambm permitir definir o tipo de caracteres ("ISO-8859-1" por omisso). Caso este tipo seja usado nos canais associados a sockets e a ficheiros, o Java nunca faz converso de tipos, permitindo transmitir dados arbitrrios (imagens, aplicaes, etc.).
// Para leitura FileInputStream f= new FileInputStream ( file ); // Para escrita FileOutputStream fos= new FileOutputStream(file); OutputStreamWriter osr= new OutputStreamWriter(fos, "8859_1"); BufferedWriter os= new BufferedWriter(osr); // Permitem ler e escrever 'char []' com os mtodos 'read' e 'write' // usando o mtodo 'getBytes()' possvel converter um 'char []' em 'byte []'

3.5 Estruturas de dados adicionais


A linguagem Java suporta um conjunto de variado de estruturas de dados que permitem lidar de uma forma eficaz com conjuntos de pares (nome de propriedade, valor de propriedade), onde o campo nome_de propriedade nico. Uma das estruturas que permite lidar com este tipo de dados a classe Properties. Esta classe usada para manter as variveis de sistema. Uma varivel da classe Properties pode ser iniciada vazia ou a partir do contedo de um ficheiro de texto, pode-se acrescentar ou remover elementos, pode-se pesquisar por nome de propriedade ou exaustivamente, e pode-se exportar o contedo para um ficheiro.

13

Properties prop= new Properties(); try { prop.load(in) } catch (IOException e) {} prop.setProperty(nome, valor); String val= prop.getProperty(nome); String val2= prop.getProperty(nome2, omisso); // L ficheiro // define valor // obtm valor // obtm valor, se n existe devolve omisso for (Enumeration p= prop.propertyNames(); p.hasMoreElements();) // percorre lista System.out.println(p.nextElement()); try { prop.store(new FileOutputStream(file), Configurao:); } catch (IOException e) { } // Grava ficheiro

3.6 Carregamento de classes em tempo real


A linguagem Java permite que novas classes sejam acrescentadas em tempo real a um programa activo, e que novos objectos dessas classes sejam usados. Uma das maneiras mais simples de lidar com os novos objectos fazer com que eles herdem os mtodos de uma interface ou classe genrica, usando-se os novos objectos atravs dessa interface. O cdigo seguinte exemplifica esta utilizao com uma classe abstracta pura Cooklet e uma classe definida DemoCooklet, que implementa todos os mtodos indefinidos na classe raiz. A classe Cooklet define todos os mtodos disponveis para lidar com novos objectos e o comportamento por omisso de cada um dos mtodos.
public abstract class Cooklet { /** Initialization method */ public void initialize() { /* Default initialization */ } /** Work method */ public abstract void work(); /** Termination method */ public void terminate() { /* Default termnation */ } }

A classe DemoCooklet herda da classe Cooklet estes comportamentos, e redefine todos os mtodos especficos.
public class DemoCooklet extends Cooklet { /** Creates a new instance of Cooklet */ public DemoCooklet() { } /** Initialization method */ public void initialize() { System.out.println("DemoCooklet initialized"); } /** Work method */ public void work() { System.out.println("DemoCooklet working"); } /** Termination method */ public void terminate() { System.out.println("DemoCooklet shut down"); } }

O carregamento de uma nova classe realizado atravs do mtodo Class.forName, que devolve um objecto do tipo Class. O ficheiro name.class dever estar acessvel no CLASSPATH. O mtodo newInstance cria um novo objecto do tipo nome, que acedido atravs dos mtodos definidos na classe abstracta Cooklet.

14

private void load_class(String name) { Cooklet cooklet = null; try { Class demoClass= Class.forName(name); Object demoObject= demoClass.newInstance(); cooklet= (Cooklet)demoObject; } catch (Exception e) { System.err.println ("Error loading class:"+e); } if (cooklet == null) { Log("null object"); return; } cooklet.initialize(); cooklet.work(); cooklet.terminate(); } // Loads class name // Creates new object

4. ESPECIFICAES
Pretende-se neste trabalho realizar um servidor Web que permita explorar vrias funcionalidades das duas verses do protocolo HTTP. No se pretende uma realizao completa do protocolo, mas uma realizao medida, com uma interface grfica que permita configurar o servidor de uma forma simples. 4.1 Especificao detalhada O servidor HTTP deve permitir suportar vrios clientes em paralelo, recorrendo a tarefas individuais para responder a cada cliente. Deve ainda manter sempre uma tarefa disponvel para receber os eventos grficos. Na interface grfica dever permitir arrancar e parar o servidor, definir o nmero de porto do servidor, e o nmero mximo de clientes que pode ter em paralelo. Para facilitar o desenvolvimento, fornecido o cdigo do servidor web bsico apresentado no exemplo 3.2.4 (pg. 10) integrado com a seguinte interface grfica:

O servidor deve receber pedidos no porto Port desde que o toggleButton Active esteja seleccionado. O campo Html define a directoria raiz, a partir de onde se procuram os ficheiros

15

nos acessos ao servidor Web local. URLs com nomes de ficheiros terminados em cgi (e.g. nome.cgi) so tratados como pedidos para objectos da classe nome, no sendo lidos da directoria anterior. O valor de Keep-Alive apenas usado caso se mantenha uma ligao aberta, em HTTP 1.1. Keep-Alive define o nmero de segundo mximo de inactividade at que se desligue a ligao (0 significa que no se desliga). Threads indica o nmero de ligaes de clientes activas num instante, e Max define o nmero mximo de ligaes que podem estar activas. Note que sempre que o nmero mximo de ligaes atingido, deve ser sempre desligada uma das ligaes para no bloquear o servidor web. Finalmente, o boto Clear limpa a janela de texto. 4.2 Interface de programao para objectos JavaCGI Qualquer classe que realize um objecto JavaCGI deve estender a classe JavaCGI, seguindo-se a abordagem apresentada na seco 3.6. A classe JavaCGI define os mtodos representados na figura seguinte.
public abstract class JavaCGI { /** Runs GET method --By default returns "not supported" */ public boolean doGet(Socket s, OutputStream out, PrintStream pout, Properties param, Properties cookies, String text) { } /** Runs POST method --By default returns "not supported" */

public boolean doPost(Socket s, OutputStream out, PrintStream pout, Properties param, Properties cookies, Properties fields) { } /** Converts CGI string into Java string (ISO-8859-1) (removes formating codes) */ public static String cgiString2string(String in_s) { } /** Converts java string (ISO-8859-1) to HTML format */ public static String String2htmlString(String in_s) { } /** Convert CGI string (ISO-8859-1) to HTML format */ public static String cgiString2htmlString(String in_s) { } }

O mtodo doGet usado sempre que invocada uma operao GET sobre um ficheiro com a extenso .cgi. Este mtodo recebe como argumentos o socket da ligao TCP (s), os dois feixes de escrita no socket (out e pout), a lista de cabealhos recebidos no pedido HTTP excluindo os cookies (param), a lista de cookies recebidos no pedido http (cookies), e o campo de dados do pedido (text). Por omisso o mtodo retorna uma pgina com o cdigo 501 (no implementado), mas o mtodo pode ser redefinido nas classes que a estendem. O mtodo doPost usado sempre que invocada uma operao POST sobre um ficheiro com a extenso .cgi. No so suportados POST sobre ficheiros com outros nomes. Este mtodo tem quase todos os argumentos semelhantes ao mtodo doGet, excepto os dados (parmetros do formulrio com a estrutura representada na pgina 5) que so passados sobre a forma de uma lista (fields). A classe JavaCGI define ainda um conjunto de funes para converso o formato de strings. O cdigo do servidor deve ler integralmente todos os campos dos pedidos HTTP, e criar as listas que passa para o objecto JavaCGI. Por sua vez, as funes devem escrever o contedo da pgina HTML directamente no out e no pout. Para efeitos de teste desta funcionalidade, fornecida juntamente com o enunciado a classe rit2CGI, que realiza uma pgina dinmica de teste que permite manter uma lista de grupos, com
16

os membros de cada grupo, e conta o nmero de actualizaes para cada grupo. A classe suporta os dois mtodos (GET e POST), e mantm uma base de dados em memria dos grupos (grupos) e em ficheiro (grupos.txt), que mantm sincronizadas. fornecido aos alunos o ficheiro rit2CGI.java que suporta todas as funcionalidades de escrita da pgina HTML para o browser, e de gesto da base de dados, FALTANDO APENAS PROGRAMAR O TRATAMENTO DOS COOKIES de forma a que: Um browser que inscreva um grupo na pgina rit2CGI.cgi, veja os dados do grupo sempre que tornar a visitar a pgina (GET) no futuro; Que pare de visualizar a pgina apenas quando fizer um POST de um grupo vazio; Que sempre que o contador esteja seleccionado, conte mais uma actualizao e apresente o nmero de vezes que o grupo foi actualizado. 4.3 Testes O servidor web dever ser compatvel com qualquer browser, com qualquer das opes ligadas. Assim, recomenda-se que sigam as especificaes indicadas na norma HTTP e evitem adoptar configuraes especficas para alguns browsers. Sempre que se seleccione ou cancele uma opo, o servidor deve cancelar os efeitos da configurao anterior, sempre que possvel (e.g. arrancar e parar o servidor). No mnimo, o servidor dever suportar pedidos (GET) de ficheiros normais mantendo a sesso aberta sempre que o browser o indicar. Deve tambm ler todos os campos de cabealho e interpretar no mnimo os seguintes cabealhos (Connection, Keep-Alive, If-Modified-Since). O servidor dever sempre devolver os campos Date, Server, Last modified, Content-Type, Content-Length, e Content-Encoding. Para ambicionarem a uma boa nota, dever-se- tambm desenvolver a interaco com pginas JavaCGI. Chama-se a ateno para os problemas de segurana que um servidor web poder representar para o contedo da vossa rea. Assim, caso realize a parte opcional do servidor Web, recomenda-se que se devolva um erro sempre que: for pedido o contedo de um directrio o nome do ficheiro incluir .. o nome do ficheiro incluir .java Atendendo grande difuso de realizaes de servidores e procuradores Web disponveis na Internet, alerta-se os alunos que no devem usar cdigo que no conheam ou consigam interpretar, pois a discusso vai focar todos os aspectos do cdigo e da realizao do servidor. 4.4 Desenvolvimento do trabalho O trabalho vai ser desenvolvido em cinco semanas. Prope-se que sejam definidas as seguintes metas para a realizao do trabalho: 0. antes da primeira aula deve ler a documentao e o cdigo fornecido; 1. no fim da primeira aula deve ter realizado a leitura de todos os campos de cabealho do pedido e preparado um cabealho para as pginas retornadas pelo servidor; 2. no fim da segunda aula deve ter programado a reutilizao de ligaes com HTTP/1.1, e a validao do "If-Modified-Since"; 3. no fim da terceira aula deve ter programado o carregamento de classes CGI, e a passagem de parmetros para os objectos JavaCGI; 4. no fim da quarta aula deve ter realizado todo o cdigo de leitura de cookies, e programado toda a gesto de cookies no ficheiro rit2CGI.java;

17

5. no fim da ltima aula deve ter acabado todas as tarefas anteriores, e ter realizado vrios testes. No esquecer que possvel fazer um "POST" com um "GET" utilizando-se um "?" no URL. 4.5 Postura dos Alunos Cada grupo deve ter em considerao o seguinte:

No perca tempo com a esttica de entrada e sada de dados Programe de acordo com os princpios gerais de uma boa codificao (utilizao de indentao, apresentao de comentrios, uso de variveis com nomes conformes s suas funes...) e Proceda de modo a que o trabalho a fazer fique equitativamente distribudo pelos dois membros do grupo.

BIBLIOGRAFIA
[1] [2] [3] [4] [5] [6] [7] James Marshall, HTTP made really easy, http://www.jmarshall.com/easy/http HTTP 1.0, http://www.ietf.org/rfc/rfc1945.txt HTTP 1.1, http://www.ietf.org/rfc/rfc2616.txt Andrew S. Tanenbaum, Computer Networks 4th Edition HTTP State Management Mechanism, http://ftp.di.fct.unl.pt/pub/documents/rfc/rfc2109.txt Hypertext Markup Language - 2.0, http://www.ietf.org/rfc/rfc1866.txt Nik Silver, "CGI Tutorial", http://www.comp.leeds.ac.uk/Perl/Cgi/start.html

DATAS LIMITE
A parte laboratorial composta por dois trabalhos de avaliao. A durao prevista para cada um deles de 5 semanas. A parte prtica tem o seu incio formal na semana de 27 de Fevereiro.

18

O quadro seguinte mostra as datas provisrias de entrega de cada trabalho de avaliao (P) e as datas previstas para os testes tericos (T). Estas datas podero ser modificadas na reunio de preparao do semestre, em 22 de Fevereiro: Fevereiro 2006
1 5 12 19 1 26 2 Maro 2006 2 5 3 12 4 19 5 26 6 6 13 20 27 7 14 21 C 8 15 22 2 9 16 23 3 10 17 24 4 11 18 25

Abril 2006 6 7 8 9 10 11 12 13 14
1 2 9 P 23 3 10 17 24 4 11 18 25

T1
12 19 26

6 13 20 27

7 14 21 28

8 15 22 29

Maio 2006
1 6 13 20 27 7 14 21 28 8 15 22 29 2 9 16 23 3 10 17 24 31 4 11 18 25 30 7 14 21 28 1 8 15 22 29 2 9 16 23 30 3 10 4 5 12 19 26 2 6 13 20 27 3

L2
18 25 1

T2
24 31

L1

19

Das könnte Ihnen auch gefallen