Skip to content

Instantly share code, notes, and snippets.

@Viacheslav77
Created November 22, 2016 14:35
Show Gist options
  • Save Viacheslav77/edcf5b9bff7e378da451323b694b8a56 to your computer and use it in GitHub Desktop.
Save Viacheslav77/edcf5b9bff7e378da451323b694b8a56 to your computer and use it in GitHub Desktop.
HTTP Server c кэшем, время жизни которого 20с.
package com.company.HTTPServer;
import java.io.*;
import java.util.List;
public class Chunker implements Processor {
private int chunkSize = 20;
public Chunker(int chunkSize) {
this.chunkSize = chunkSize;
}
public int getChunkSize() {
return chunkSize;
}
public void setChunkSize(int value) {
chunkSize = value;
}
public byte[] process(byte[] data, List<String> headers) {
try {
ByteArrayOutputStream os = new ByteArrayOutputStream();
int n = data.length / chunkSize;
int tail = data.length % chunkSize;
int offset = 0;
String head = Integer.toHexString(chunkSize) + "\r\n";
for (int i = 0; i < n; i++) {
os.write(head.getBytes());
os.write(data, offset, chunkSize);
os.write("\r\n".getBytes());
offset += chunkSize;
}
if (tail > 0) {
head = Integer.toHexString(tail) + "\r\n";
os.write(head.getBytes());
os.write(data, offset, tail);
os.write("\r\n".getBytes());
}
os.write("0\r\n\r\n".getBytes());
headers.add("Transfer-Encoding: chunked\r\n");
return os.toByteArray();
} catch (IOException ex) {
return null;
}
}
}
package com.company.HTTPServer;
import java.io.*;
import java.util.List;
import java.util.zip.*;
public class Compressor implements Processor {
public static final int ALG_DEFLATE = 0;
public static final int ALG_GZIP = 1;
private int compLevel = 6;
private int compAlg = ALG_GZIP;
public Compressor(int compLevel) {
this.compLevel = compLevel;
}
public int getCompressionLevel() {
return compLevel;
}
public void setCompressionLevel(int value) {
compLevel = value;
}
public int getCompressionAlg() {
return compAlg;
}
public void setCompressionAlg(int value) {
compAlg = value;
}
public byte[] process(byte[] data, List<String> headers) {
try {
ByteArrayOutputStream os = new ByteArrayOutputStream();
if (compAlg == ALG_DEFLATE) {
DeflaterOutputStream ds = new DeflaterOutputStream(os, new Deflater(compLevel));
ds.write(data);
ds.finish();
headers.add("Content-Encoding: deflated\r\n");
} else if (compAlg == ALG_GZIP) {
GZIPOutputStream ds = new GZIPOutputStream(os);
ds.write(data);
ds.finish();
headers.add("Content-Encoding: gzip\r\n");
}
return os.toByteArray();
} catch (IOException ex) {
return null;
}
}
}
Server started 1...
GET / HTTP/1.1
Host: 127.0.0.1:8080
Connection: keep-alive
Cache-Control: max-age=0
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.99 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
Accept-Encoding: gzip, deflate, sdch, br
Accept-Language: uk-UA,uk;q=0.8,ru;q=0.6,en-US;q=0.4,en;q=0.2
---------------------------------------------
/index.html
Page from the HDD ... The lifetime of the cashe = -1.479
GET /favicon.ico HTTP/1.1
Host: 127.0.0.1:8080
Connection: keep-alive
Pragma: no-cache
Cache-Control: no-cache
User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.99 Safari/537.36
Accept: */*
Referer: http://127.0.0.1:8080/
Accept-Encoding: gzip, deflate, sdch, br
Accept-Language: uk-UA,uk;q=0.8,ru;q=0.6,en-US;q=0.4,en;q=0.2
---------------------------------------------
/favicon.ico
Page from the HDD ... The lifetime of the cashe = 19.876
GET / HTTP/1.1
Host: 127.0.0.1:8080
Connection: keep-alive
Cache-Control: max-age=0
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.99 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
Accept-Encoding: gzip, deflate, sdch, br
Accept-Language: uk-UA,uk;q=0.8,ru;q=0.6,en-US;q=0.4,en;q=0.2
---------------------------------------------
/index.html
Page from the cache ... The lifetime of the cashe = 17.298
GET /favicon.ico HTTP/1.1
Host: 127.0.0.1:8080
Connection: keep-alive
Pragma: no-cache
Cache-Control: no-cache
User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.99 Safari/537.36
Accept: */*
Referer: http://127.0.0.1:8080/
Accept-Encoding: gzip, deflate, sdch, br
Accept-Language: uk-UA,uk;q=0.8,ru;q=0.6,en-US;q=0.4,en;q=0.2
---------------------------------------------
/favicon.ico
Page from the HDD ... The lifetime of the cashe = 16.990
GET / HTTP/1.1
Host: 127.0.0.1:8080
Connection: keep-alive
Cache-Control: max-age=0
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.99 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
Accept-Encoding: gzip, deflate, sdch, br
Accept-Language: uk-UA,uk;q=0.8,ru;q=0.6,en-US;q=0.4,en;q=0.2
---------------------------------------------
/index.html
Page from the cache ... The lifetime of the cashe = 18.5
GET /favicon.ico HTTP/1.1
Host: 127.0.0.1:8080
Connection: keep-alive
Pragma: no-cache
Cache-Control: no-cache
User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.99 Safari/537.36
Accept: */*
Referer: http://127.0.0.1:8080/
Accept-Encoding: gzip, deflate, sdch, br
Accept-Language: uk-UA,uk;q=0.8,ru;q=0.6,en-US;q=0.4,en;q=0.2
---------------------------------------------
/favicon.ico
Page from the HDD ... The lifetime of the cashe = 18.177
GET / HTTP/1.1
Host: 127.0.0.1:8080
Connection: keep-alive
Cache-Control: max-age=0
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.99 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
Accept-Encoding: gzip, deflate, sdch, br
Accept-Language: uk-UA,uk;q=0.8,ru;q=0.6,en-US;q=0.4,en;q=0.2
---------------------------------------------
/index.html
Page from the cache ... The lifetime of the cashe = 1.306
GET /favicon.ico HTTP/1.1
Host: 127.0.0.1:8080
Connection: keep-alive
Pragma: no-cache
Cache-Control: no-cache
User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.99 Safari/537.36
Accept: */*
Referer: http://127.0.0.1:8080/
Accept-Encoding: gzip, deflate, sdch, br
Accept-Language: uk-UA,uk;q=0.8,ru;q=0.6,en-US;q=0.4,en;q=0.2
---------------------------------------------
/favicon.ico
Page from the HDD ... The lifetime of the cashe = 1.074
package com.company.HTTPServer;
import java.io.*;
import java.util.concurrent.ConcurrentHashMap;
public class FileManager {
private String path;
private long lifeTime = 20000;
private static long beginTime = 0;
private static ConcurrentHashMap<String, byte[]> map = new ConcurrentHashMap<String, byte[]>();
public FileManager(String path) {
if (path.endsWith("/") || path.endsWith("\\"))
path = path.substring(0, path.length() - 1);
this.path = path;
}
public byte[] get(String url) {
System.out.println(url);
try {
if( System.currentTimeMillis() <= beginTime && map.containsKey(url)){
System.out.println("\nPage from the cache ... The lifetime of the cashe = " + (beginTime- System.currentTimeMillis())*0.001+"\n");
return map.get(url);
}
else {
System.out.println("\nPage from the HDD ... The lifetime of the cashe = " + (beginTime- System.currentTimeMillis())*0.001 + "\n");
String fullPath = path + url.replace('/', '\\');
beginTime = System.currentTimeMillis()+lifeTime;
byte[] buf;
try (RandomAccessFile f = new RandomAccessFile(fullPath, "r"))
{
buf = new byte[(int)f.length()];
f.read(buf, 0, buf.length);
}
map.put(url, buf);
return buf;
}
} catch (IOException ex) {
return null;
}
}
}
package com.company.HTTPServer;
import java.lang.Exception;
import java.io.*;
import java.net.*;
import java.util.ArrayList;
import java.util.List;
import java.lang.Thread;
public class Client extends Thread {
private Socket socket;
private List<Client> clients;
private FileManager fm;
public Client(Socket socket, List<Client> clients, String path) {
this.socket = socket;
this.clients = clients;
fm = new FileManager(path);
}
private void return400(OutputStream os) throws IOException {
byte[] resp = "HTTP/1.1 400 Bad Request\r\n\r\n".getBytes();
os.write(resp);
}
private byte[] getBinaryHeaders(List<String> headers) {
StringBuilder res = new StringBuilder();
for (String s : headers)
res.append(s);
return res.toString().getBytes();
}
private void process(String request, OutputStream os) throws IOException {
System.out.println(request);
System.out.println("---------------------------------------------");
int idx = request.indexOf("\r\n");
request = request.substring(0, idx);
String[] parts = request.split(" ");
if (parts.length != 3) {
return400(os);
return;
}
String req = parts[0], url = parts[1], http = parts[2];
if (( ! http.equalsIgnoreCase("HTTP/1.0")) && ( ! http.equalsIgnoreCase("HTTP/1.1"))) {
return400(os);
return;
}
if ( ! req.equalsIgnoreCase("GET")) {
return400(os);
return;
}
if ("/".equals(url))
url = "/index.html";
List<String> headers = new ArrayList<String>();
headers.add("HTTP/1.1 200 OK\r\n");
byte[] content = fm.get(url);
ProcessorsList pl = new ProcessorsList();
pl.add(new Compressor(9));
pl.add(new Chunker(30)); // comment
content = pl.process(content, headers);
if (content != null) {
// uncomment next line
//headers.add("Content-Length: " + content.length + "\r\n");
headers.add("Connection: close\r\n\r\n");
os.write(getBinaryHeaders(headers));
os.write(content);
} else {
byte[] resp = "HTTP/1.1 404 Not Found\r\n\r\n".getBytes();
os.write(resp);
}
}
@Override
public void run() {
try {
InputStream is = socket.getInputStream();
OutputStream os = socket.getOutputStream();
int r, offset = 0;
byte[] buf = new byte[10240];
do {
r = is.read(buf, offset, buf.length - offset);
if (r > 0) {
offset += r;
for (int i = 0; i < offset; i++) {
if (buf[i] == (byte)13) {
if ((i + 3 < offset) &&
(buf[i + 1] == (byte)10) &&
(buf[i + 2] == (byte)13) &&
(buf[i + 3] == (byte)10))
{
String request = new String(buf, 0, offset - 4);
buf = new byte[10240];
offset = 0;
process(request, os);
}
}
}
}
} while ( ! isInterrupted());
clients.remove(this);
} catch (Exception ex) {
return;
}
}
}
package com.company.HTTPServer;
import java.net.*;
import java.util.ArrayList;
import java.util.List;
import java.lang.Thread;
public class HTTPServer {
private int port;
private String path;
private Thread listenThread;
private List<Client> clients = new ArrayList<Client>();
public HTTPServer(int port) {
this.port = port;
}
public void start() {
listenThread = new Thread() {
public void run() {
try {
ServerSocket srv = new ServerSocket(port);
try {
while ( ! isInterrupted()) {
Client client = new Client(srv.accept(), clients, path);
clients.add(client);
client.start();
Thread.sleep(50);
}
} finally {
srv.close();
}
} catch (Exception ex) {
return;
}
}
};
listenThread.start();
}
public void stop() {
listenThread.interrupt();
for (Client client : clients)
client.interrupt();
}
public void setPath(String path) {
this.path = path;
}
}
package com.company.HTTPServer;
import java.lang.Thread;
public class Main {
public static void main(String[] args) {
final HTTPServer server = new HTTPServer(8080);
server.setPath("D:\\1\\tmp");
server.start();
System.out.println("Server started m...");
Runtime.getRuntime().addShutdownHook(new Thread() {
public void run() {
server.stop();
System.out.println("Server stopped!");
}
});
}
}
package com.company.HTTPServer;
import java.util.List;
public interface Processor {
byte[] process(byte[] data, List<String> headers);
}
package com.company.HTTPServer;
import java.util.ArrayList;
import java.util.List;
public class ProcessorsList implements Processor {
private List<Processor> list = new ArrayList<Processor>();
public void add(Processor p) {
list.add(p);
}
public byte[] process(byte[] data, List<String> headers) {
byte[] res = data;
for (Processor p : list)
res = p.process(res, headers);
return res;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment