Commit d3441d0e authored by Sefa Eyeoglu's avatar Sefa Eyeoglu

Initial commit

parents
# Created by .ignore support plugin (hsz.mobi)
### Java template
# Compiled class file
*.class
# Log file
*.log
# BlueJ files
*.ctxt
# Mobile Tools for Java (J2ME)
.mtj.tmp/
# Package Files #
*.jar
*.war
*.ear
*.zip
*.tar.gz
*.rar
# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
hs_err_pid*
### Windows template
# Windows thumbnail cache files
Thumbs.db
ehthumbs.db
ehthumbs_vista.db
# Folder config file
Desktop.ini
# Recycle Bin used on file shares
$RECYCLE.BIN/
# Windows Installer files
*.cab
*.msi
*.msm
*.msp
# Windows shortcuts
*.lnk
### Maven template
target/
pom.xml.tag
pom.xml.releaseBackup
pom.xml.versionsBackup
pom.xml.next
release.properties
dependency-reduced-pom.xml
buildNumber.properties
.mvn/timing.properties
# Avoid ignoring Maven wrapper jar file (.jar files are usually ignored)
!/.mvn/wrapper/maven-wrapper.jar
### JetBrains template
# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and Webstorm
# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839
.idea
## File-based project format:
*.iws
## Plugin-specific files:
# IntelliJ
/out/
# mpeltonen/sbt-idea plugin
.idea_modules/
# JIRA plugin
atlassian-ide-plugin.xml
# Crashlytics plugin (for Android Studio and IntelliJ)
com_crashlytics_export_strings.xml
crashlytics.properties
crashlytics-build.properties
fabric.properties
This diff is collapsed.
Copyright 2017 Sefa Eyeoglu
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
\ No newline at end of file
# Implify
A Java HTTP server.
## License
This project is licensed under the Apache License 2.0. You can find more information in the *NOTICE* file
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>net.scrumplex</groupId>
<artifactId>implify</artifactId>
<version>0.0.1</version>
<dependencies>
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.5</version>
</dependency>
</dependencies>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.build.timestamp.format>dd-MM-yyyy'T'HH:mm:ss'Z'</maven.build.timestamp.format>
</properties>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.5.1</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
<showDeprecation>true</showDeprecation>
<showWarnings>true</showWarnings>
<executable>javac</executable>
<fork>true</fork>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-assembly-plugin</artifactId>
<version>2.6</version>
<configuration>
<archive>
<manifest>
<mainClass>net.scrumplex.sprummlbot.Main</mainClass>
</manifest>
</archive>
<descriptorRefs>
<descriptorRef>jar-with-dependencies</descriptorRef>
</descriptorRefs>
<finalName>sprummlbot-full</finalName>
<appendAssemblyId>false</appendAssemblyId>
</configuration>
</plugin>
</plugins>
</build>
</project>
\ No newline at end of file
package net.scrumplex.implify;
import net.scrumplex.implify.core.ImplifyServer;
public class Main {
public static void main(String[] args) {
ImplifyServer httpd = new ImplifyServer(8080, 1234);
httpd.start();
}
}
package net.scrumplex.implify.concurrent;
import net.scrumplex.implify.core.ImplifyServer;
import java.util.concurrent.ThreadFactory;
public class ImplifyThreadFactory implements ThreadFactory {
private ImplifyServer serverInstance;
public ImplifyThreadFactory(ImplifyServer serverInstance) {
this.serverInstance = serverInstance;
}
public Thread newThread(Runnable r) {
return newThread(r, null);
}
public Thread newThread(Runnable r, String context) {
Thread t = new Thread(r);
t.setName(context == null ? "implify_" + t.getId() : context);
t.setPriority(8);
t.setUncaughtExceptionHandler(serverInstance.getExceptionHandler());
return t;
}
}
package net.scrumplex.implify.core;
import net.scrumplex.implify.concurrent.ImplifyThreadFactory;
import net.scrumplex.implify.core.lang.HTTPHandler;
import net.scrumplex.implify.core.lang.RawHandler;
import net.scrumplex.implify.core.request.HTTPRequestHandler;
import net.scrumplex.implify.core.request.RawSocketHandler;
import net.scrumplex.implify.exceptions.ImplifyExceptionHandler;
import java.io.File;
import java.io.IOException;
import java.net.InetAddress;
import java.net.ServerSocket;
import java.net.Socket;
public class ImplifyServer {
private final String ip;
private final int port;
private final int backlog;
private final int identifier;
private ImplifyExceptionHandler exceptionHandler;
private ImplifyThreadFactory threadFactory;
private RawHandler rawSocketHandler;
private HTTPHandler httpHandler;
private ServerSocket serverSocket;
private Thread mainThread;
public ImplifyServer(int port, int identifier) {
this("0.0.0.0", port, identifier);
}
public ImplifyServer(String ip, int port, int identifier) {
this(ip, port, 1024, identifier);
}
public ImplifyServer(String ip, int port, int backlog, int identifier) {
this.ip = ip;
this.port = port;
this.backlog = backlog;
this.identifier = identifier;
initialize();
}
private void initialize() {
exceptionHandler = new ImplifyExceptionHandler(this);
threadFactory = new ImplifyThreadFactory(this);
rawSocketHandler = new RawSocketHandler(this);
try {
httpHandler = new HTTPRequestHandler(this, new File(new File(".").getCanonicalPath()));
} catch (IOException ignored) {
}
}
public void start() {
try {
serverSocket = new ServerSocket(port, backlog, InetAddress.getByName(ip));
} catch (IOException e) {
getExceptionHandler().caughtException(e, "");
}
mainThread = getThreadFactory().newThread(new Runnable() {
public void run() {
while (true) {
try {
Socket socket = serverSocket.accept();
getRawSocketHandler().handle(socket);
} catch (IOException e) {
e.printStackTrace();
getExceptionHandler().caughtException(e, "instance_" + identifier);
}
}
}
}, "implify_instance_" + identifier);
mainThread.start();
}
public void stop() {
mainThread.interrupt();
try {
if (!serverSocket.isClosed())
serverSocket.close();
} catch (IOException e) {
getExceptionHandler().caughtException(e, "stop_instance_" + identifier);
}
}
public ImplifyExceptionHandler getExceptionHandler() {
return exceptionHandler;
}
public ImplifyThreadFactory getThreadFactory() {
return threadFactory;
}
public HTTPHandler getHttpHandler() {
return httpHandler;
}
public void setHttpHandler(HTTPHandler httpHandler) {
this.httpHandler = httpHandler;
}
public RawHandler getRawSocketHandler() {
return rawSocketHandler;
}
public void setRawSocketHandler(RawHandler rawSocketHandler) {
this.rawSocketHandler = rawSocketHandler;
}
}
package net.scrumplex.implify.core.lang;
import net.scrumplex.implify.core.ImplifyServer;
import java.net.Socket;
import java.util.Map;
public class Client {
private final ImplifyServer serverInstance;
private final Socket socket;
private String requestPath;
private String requestMethod;
private String httpVersion;
private Map<String, String> headers;
public Client(ImplifyServer serverInstance, java.net.Socket socket) {
this.serverInstance = serverInstance;
this.socket = socket;
}
public String getRequestPath() {
return requestPath;
}
public void setRequestPath(String requestPath) {
this.requestPath = requestPath;
}
public String getRequestMethod() {
return requestMethod;
}
public void setRequestMethod(String requestMethod) {
this.requestMethod = requestMethod;
}
public Socket getSocket() {
return socket;
}
public String getHttpVersion() {
return httpVersion;
}
public void setHttpVersion(String httpVersion) {
this.httpVersion = httpVersion;
}
public Map<String, String> getHeaders() {
return headers;
}
public void setHeaders(Map<String, String> headers) {
this.headers = headers;
}
public ImplifyServer getServerInstance() {
return serverInstance;
}
}
package net.scrumplex.implify.core.lang;
import java.io.IOException;
import java.net.Socket;
public interface HTTPHandler {
void handle(Client client) throws IOException;
}
package net.scrumplex.implify.core.lang;
import java.io.IOException;
import java.net.Socket;
/**
* Created by Sefa Eyeoglu on 10.03.2017.
*/
public interface RawHandler {
void handle(Socket socket) throws IOException;
}
package net.scrumplex.implify.core.request;
import net.scrumplex.implify.core.ImplifyServer;
import net.scrumplex.implify.core.lang.Client;
import net.scrumplex.implify.core.lang.HTTPHandler;
import org.apache.commons.io.IOUtils;
import java.io.*;
import java.net.Socket;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Locale;
import java.util.Map;
import java.util.TimeZone;
import java.util.zip.GZIPOutputStream;
public class HTTPRequestHandler implements HTTPHandler {
private final ImplifyServer serverInstance;
private final File parentDirectory;
public HTTPRequestHandler(ImplifyServer serverInstance, File parentDirectory) {
this.serverInstance = serverInstance;
this.parentDirectory = parentDirectory;
}
public void handle(Client client) throws IOException {
Socket sock = client.getSocket();
OutputStream out = sock.getOutputStream();
DataOutputStream headersOut = new DataOutputStream(out);
//Options {
boolean compress = false;
String compressType = ""; //Only GZIP support currently
//}
Map<String, String> headers = client.getHeaders();
if (headers.containsKey("Accept-Encoding")) {
if (headers.get("Accept-Encoding").contains("gzip")) {
compress = true;
compressType = "gzip";
}
}
File f = new File(parentDirectory, client.getRequestPath().substring(1));
FileInputStream fis = new FileInputStream(f);
Calendar calendar = Calendar.getInstance();
SimpleDateFormat dateFormat = new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss z", Locale.US);
dateFormat.setTimeZone(TimeZone.getTimeZone("GMT"));
headersOut.writeBytes("HTTP/1.1 200 OK\n");
headersOut.writeBytes("Accept-Ranges: bytes\n");
headersOut.writeBytes("Connection: close\n");
if (compress)
headersOut.writeBytes("Content-Encoding: " + compressType + "\n");
if (!compress)
headersOut.writeBytes("Content-Length: " + f.length() + "\n");
headersOut.writeBytes("Content-Type: text/plain; charset=UTF-8\n");
headersOut.writeBytes("Date: " + dateFormat.format(calendar.getTime()) + "\n");
headersOut.writeBytes("Server: Implify/1.0\n");
headersOut.writeBytes("\n");
headersOut.flush();
OutputStream fileOut = compress ? new GZIPOutputStream(out) : out;
IOUtils.copy(fis, fileOut);
fileOut.close();
sock.close();
}
}
package net.scrumplex.implify.core.request;
import net.scrumplex.implify.core.ImplifyServer;
import net.scrumplex.implify.core.lang.Client;
import net.scrumplex.implify.core.lang.RawHandler;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.Socket;
import java.util.HashMap;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class RawSocketHandler implements RawHandler {
private final ImplifyServer serverInstance;
private final Pattern httpPattern;
public RawSocketHandler(ImplifyServer serverInstance) {
this.serverInstance = serverInstance;
this.httpPattern = Pattern.compile("(GET|POST)\\s(.*)HTTP\\/(\\d\\.\\d)");
}
public void handle(Socket socket) throws IOException {
BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
//DataOutputStream out = new DataOutputStream(socket.getOutputStream());
String firstLine = in.readLine();
Matcher matcher = httpPattern.matcher(firstLine);
if (!matcher.matches()) {
socket.close();
return;
}
if (!matcher.group(3).equals("1.1")) {
//TODO: HTTP Version unsupported HTTP505 error
socket.close();
return;
}
Map<String, String> headers = new HashMap<>();
String line;
while ((line = in.readLine()) != null) {
if (line.length() == 0)
break;
String[] parts = line.split(":\\s");
String headerName = parts[0];
String headerValue = parts[1];
headers.put(headerName, headerValue);
}
Client client = new Client(serverInstance, socket);
client.setRequestMethod(matcher.group(1));
client.setRequestPath(matcher.group(2));
client.setHttpVersion(matcher.group(3));
client.setHeaders(headers);
//TODO: Request Body
serverInstance.getHttpHandler().handle(client);
}
}
package net.scrumplex.implify.exceptions;
import net.scrumplex.implify.core.ImplifyServer;
public class ImplifyExceptionHandler implements Thread.UncaughtExceptionHandler {
private final ImplifyServer serverInstance;
public ImplifyExceptionHandler(ImplifyServer serverInstance) {
this.serverInstance = serverInstance;
}
public void uncaughtException(Thread t, Throwable e) {
}
public void caughtException(Throwable e, String context) {
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment