I'm studying the use of sockets and multithreading to build an HTTP server in Java, but I'm experiencing some complications. When I run the server code, it opens correctly in Internet Explorer, but in Google Chrome it does not even display the Server Index (the browser indicates an HTTP RESPONSE error).
In addition, there is another problem: even with the server running in Internet Explorer, requests for images and PDF files do not work. I thought it was something related to the Content Type, however I deal with it in the code, and yet any image or PDF file is displayed in a totally unconfigured way in the browser.
I'm studying this code, however using a HashMap
to save the data header and other modifications.
Because the program has several classes, I decided to put them together this link from Codeshare. Here is the code below:
Class ServidorHTTP
import java.io.IOException;
import java.net.ServerSocket;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
/**
* Copyright 2011 Dasanjos.com. All rights reserved.
Redistribution and use in source and binary forms, with or without modification, are
permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this list of
conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice, this list
of conditions and the following disclaimer in the documentation and/or other materials
provided with the distribution.
THIS SOFTWARE IS PROVIDED BY DASANJOS.COM ''AS IS'' AND ANY EXPRESS OR IMPLIED
WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL DASANJOS.COM OR
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
The views and conclusions contained in the software and documentation are those of the
authors and should not be interpreted as representing official policies, either expressed
or implied, of DASANJOS.COM.
*/
public class ServidorHTTP
{
private static final int porta = 8085;
public static void main( String[] args ) throws IOException
{
ServerSocket serverSocket = new ServerSocket(porta);
ExecutorService executorService = Executors.newFixedThreadPool(20);
System.out.println("O servidor está esperando solicitações da porta " + porta + "...");
while(true) {
executorService.submit(new Conexao(serverSocket.accept()));
}
}
}
Class Conexao
import java.io.IOException;
import java.net.Socket;
public class Conexao implements Runnable {
private Socket socket;
public Conexao(Socket socket) {
this.socket = socket;
}
public void run() {
try {
Requisicao requisicao = new Requisicao(socket.getInputStream());
Resposta resposta = new Resposta(requisicao);
resposta.write(socket.getOutputStream());
socket.close();
} catch (IOException e) {
System.out.println("Erro na solicitação!");
}
}
}
Class Requisicao
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.HashMap;
import java.util.Map;
public class Requisicao {
private Metodo metodoRequisicao;
private String recurso;
private String versaoProtocolo;
private Map<String, String> cabecalho = new HashMap<>();
public Requisicao(InputStream dadosCliente) throws IOException {
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(dadosCliente));
String dadosRecebidos = bufferedReader.readLine();
parsearDadosRecebidos(dadosRecebidos);
dadosRecebidos = bufferedReader.readLine();
while (!dadosRecebidos.equals("")) {
parsearCabecalho(dadosRecebidos);
dadosRecebidos = bufferedReader.readLine();
}
cabecalho.forEach((k,v)-> System.out.println(k + v));
}
private void parsearDadosRecebidos(String dadosRecebidos) {
String[] mensagemParseada = dadosRecebidos.split("\s+");
metodoRequisicao = Metodo.valueOf(mensagemParseada[0]);
recurso = mensagemParseada[1];
versaoProtocolo = mensagemParseada[2];
}
private void parsearCabecalho(String dadosRecebidos) {
String[] chaveValor = dadosRecebidos.split(":");
cabecalho.put(chaveValor[0] + ":", chaveValor[1]);
}
public Map<String, String> getCabecalho() {
return cabecalho;
}
public Metodo getMetodoRequisicao() {
return metodoRequisicao;
}
public String getRecurso() {
return recurso;
}
public String getVersaoProtocolo() {
return versaoProtocolo;
}
}
Class Resposta
import java.io.*;
import java.util.HashMap;
import java.util.Map;
public class Resposta {
private Map<String, String> cabecalhoResposta = new HashMap<>();
private String versaoProtocolo = "HTTP/1.1";
private byte[] corpoMensagem;
public Resposta(Requisicao requisicao) throws IOException {
switch (requisicao.getMetodoRequisicao()) {
case GET:
try {
formarCabecalho(StatusCode.statusCode_200);
File arquivo = new File("." + requisicao.getRecurso());
if (arquivo.isDirectory()) {
cabecalhoResposta.put("Content-Type: ", ExtensaoRecurso.HTML.getExtensaoRecurso());
StringBuilder raizServidor = new StringBuilder("<html><head><title>Index of ");
raizServidor.append(requisicao.getRecurso());
raizServidor.append("</title></head><body><h1>Index of ");
raizServidor.append(requisicao.getRecurso());
raizServidor.append("</h1><hr><pre>");
File[] arquivos = arquivo.listFiles();
for (File subfile : arquivos) {
raizServidor.append(" <a href=\"" + subfile.getPath() + "\">" + subfile.getPath() + "</a>\n");
}
raizServidor.append("<hr></pre></body></html>");
formarResposta(raizServidor.toString());
} else if (arquivo.exists()) {
definirTipoConteudo(requisicao.getRecurso(), cabecalhoResposta);
formarResposta(getBytes(arquivo));
} else {
formarCabecalho(StatusCode.statusCode_404);
formarResposta(StatusCode.statusCode_404.getDescricaoMensagem());
}
} catch (Exception e) {
formarCabecalho(StatusCode.statusCode_400);
formarResposta(StatusCode.statusCode_400.getDescricaoMensagem());
}
break;
case POST:
formarCabecalho(StatusCode.statusCode_201);
break;
default:
formarCabecalho(StatusCode.statusCode_500);
formarResposta(StatusCode.statusCode_500.getDescricaoMensagem());
}
}
private void formarResposta(String resposta) {
corpoMensagem = resposta.getBytes();
}
private void formarResposta(byte[] resposta) {
corpoMensagem = resposta;
}
private void formarCabecalho(StatusCode statusCode) {
cabecalhoResposta.put(versaoProtocolo + " ", statusCode.getDescricaoMensagem());
cabecalhoResposta.put("Connection: ", "close");
cabecalhoResposta.put("Server: ", "ServidorHTTP");
}
private void definirTipoConteudo(String recurso, Map<String, String> cabecalhoResposta) {
try {
String extensaoArquivo = recurso.substring(recurso.indexOf(".") + 1);
cabecalhoResposta.put("Content-Type: ", ExtensaoRecurso.valueOf(extensaoArquivo.toUpperCase()).getExtensaoRecurso());
System.out.println(cabecalhoResposta);
} catch (Exception e) {
System.out.println("Conteúdo do arquivo não aceito pelo servidor!");
}
}
private byte[] getBytes(File file) throws IOException {
int length = (int) file.length();
byte[] array = new byte[length];
InputStream in = new FileInputStream(file);
int offset = 0;
while (offset < length) {
int count = in.read(array, offset, (length - offset));
offset += count;
}
in.close();
return array;
}
public void write(OutputStream os) throws IOException {
DataOutputStream output = new DataOutputStream(os);
for(Map.Entry<String,String> pair : cabecalhoResposta.entrySet()) {
String chaveValor = pair.getKey() + pair.getValue();
output.writeBytes(chaveValor + "\r\n");
System.out.println(chaveValor);
}
output.writeBytes("\r\n");
if (corpoMensagem != null) {
output.write(corpoMensagem);
}
output.writeBytes("\r\n");
output.flush();
}
}
Enum StatusCode
public enum StatusCode {
statusCode_200("200 OK"),
statusCode_201("201 Created"),
statusCode_301("301 Moved Permanently"),
statusCode_400("400 Bad Request"),
statusCode_401("401 Unauthorized"),
statusCode_404("404 Not Found"),
statusCode_500("500 Internal Server Error");
private String descricaoMensagem;
StatusCode(String descricaoMensagem) {
this.descricaoMensagem = descricaoMensagem;
}
public String getDescricaoMensagem() {
return descricaoMensagem;
}
}
Enum Metodo
public enum Metodo {
GET("GET"),
POST("POST");
private String nomeMetodo;
Metodo(String nomeMetodo) {
this.nomeMetodo = nomeMetodo;
}
public void setNomeMetodo(String nomeMetodo) {
this.nomeMetodo = nomeMetodo;
}
public String getNomeMetodo() {
return nomeMetodo;
}
}
Enum ExtensaoRecurso
public enum ExtensaoRecurso {
PNG("image/png"),
JPG("image/jpeg"),
JPEG("image/jpeg"),
TXT("text/plain"),
HTML("text/html"),
CSS("text/css"),
GIF("image/gif"),
PDF("application/pdf"),
XML("text/xml");
private String extensaoRecurso;
ExtensaoRecurso(String extensaoRecurso) {
this.extensaoRecurso = extensaoRecurso;
}
public String getExtensaoRecurso() {
return extensaoRecurso;
}
}