Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

<DO NOT MERGE> OkHttpServer v0 #2912

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
48 changes: 48 additions & 0 deletions okhttp-server/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
OkWebServer
=============

A modern HTTP Web Server


### Motivation

...

### Example

...

### API

...


### Download

Get OkWebServer via Maven:
```xml
<dependency>
<groupId>com.squareup.okhttp3</groupId>
<artifactId>okwebserver</artifactId>
<version>(insert latest version)</version>
</dependency>
```

or via Gradle
```groovy
testCompile 'com.squareup.okhttp3:okwebserver:(insert latest version)'
```

### License

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.
69 changes: 69 additions & 0 deletions okhttp-server/pom.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
<?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/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>

<parent>
<groupId>com.squareup.okhttp3</groupId>
<artifactId>parent</artifactId>
<version>3.5.0-SNAPSHOT</version>
</parent>

<artifactId>okwebserver</artifactId>
<name>OkWebServer</name>

<dependencies>
<dependency>
<groupId>${project.groupId}</groupId>
<artifactId>okhttp</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>${project.groupId}</groupId>
<artifactId>okhttp-testing-support</artifactId>
<version>${project.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.bouncycastle</groupId>
<artifactId>bcprov-jdk15on</artifactId>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<scope>test</scope>
</dependency>
</dependencies>

<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-javadoc-plugin</artifactId>
<configuration>
<links>
<link>http://square.github.io/okhttp/javadoc/</link>
<link>http://square.github.io/okio/</link>
</links>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-assembly-plugin</artifactId>
<configuration>
<descriptorRefs>
<descriptorRef>jar-with-dependencies</descriptorRef>
</descriptorRefs>
</configuration>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>single</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
188 changes: 188 additions & 0 deletions okhttp-server/src/main/java/okhttp3/internal/http2/Http2Server.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,188 @@
/*
* Copyright (C) 2011 The Android Open Source Project
*
* 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.
*/

package okhttp3.internal.http2;

import java.io.File;
import java.io.IOException;
import java.net.ProtocolException;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.net.ssl.SSLSocket;
import javax.net.ssl.SSLSocketFactory;
import okhttp3.Protocol;
import okhttp3.internal.Util;
import okhttp3.internal.platform.Platform;
import okhttp3.internal.tls.SslClient;
import okio.BufferedSink;
import okio.Okio;
import okio.Source;

import static okhttp3.internal.platform.Platform.INFO;

/** A basic HTTP/2 server that serves the contents of a local directory. */
public final class Http2Server extends Http2Connection.Listener {
static final Logger logger = Logger.getLogger(Http2Server.class.getName());

private final File baseDirectory;
private final SSLSocketFactory sslSocketFactory;

public Http2Server(File baseDirectory, SSLSocketFactory sslSocketFactory) {
this.baseDirectory = baseDirectory;
this.sslSocketFactory = sslSocketFactory;
}

private void run() throws Exception {
ServerSocket serverSocket = new ServerSocket(8888);
serverSocket.setReuseAddress(true);

while (true) {
Socket socket = null;
try {
socket = serverSocket.accept();

SSLSocket sslSocket = doSsl(socket);
String protocolString = Platform.get().getSelectedProtocol(sslSocket);
Protocol protocol = protocolString != null ? Protocol.get(protocolString) : null;
if (protocol != Protocol.HTTP_2) {
throw new ProtocolException("Protocol " + protocol + " unsupported");
}
Http2Connection connection = new Http2Connection.Builder(false)
.socket(sslSocket)
.listener(this)
.build();
connection.start();
} catch (IOException e) {
logger.log(Level.INFO, "FramedServer connection failure: " + e);
Util.closeQuietly(socket);
} catch (Exception e) {
logger.log(Level.WARNING, "FramedServer unexpected failure", e);
Util.closeQuietly(socket);
}
}
}

private SSLSocket doSsl(Socket socket) throws IOException {
SSLSocket sslSocket = (SSLSocket) sslSocketFactory.createSocket(
socket, socket.getInetAddress().getHostAddress(), socket.getPort(), true);
sslSocket.setUseClientMode(false);
Platform.get().configureTlsExtensions(sslSocket, null,
Collections.singletonList(Protocol.HTTP_2));
sslSocket.startHandshake();
return sslSocket;
}

@Override public void onStream(final Http2Stream stream) throws IOException {
try {
List<Header> requestHeaders = stream.getRequestHeaders();
String path = null;
for (int i = 0, size = requestHeaders.size(); i < size; i++) {
if (requestHeaders.get(i).name.equals(Header.TARGET_PATH)) {
path = requestHeaders.get(i).value.utf8();
break;
}
}

if (path == null) {
// TODO: send bad request error
throw new AssertionError();
}

File file = new File(baseDirectory + path);

if (file.isDirectory()) {
serveDirectory(stream, file.listFiles());
} else if (file.exists()) {
serveFile(stream, file);
} else {
send404(stream, path);
}
} catch (IOException e) {
Platform.get().log(INFO, "Failure serving FramedStream: " + e.getMessage(), null);
}
}

private void send404(Http2Stream stream, String path) throws IOException {
List<Header> responseHeaders = Arrays.asList(
new Header(":status", "404"),
new Header(":version", "HTTP/1.1"),
new Header("content-type", "text/plain")
);
stream.reply(responseHeaders, true);
BufferedSink out = Okio.buffer(stream.getSink());
out.writeUtf8("Not found: " + path);
out.close();
}

private void serveDirectory(Http2Stream stream, File[] files) throws IOException {
List<Header> responseHeaders = Arrays.asList(
new Header(":status", "200"),
new Header(":version", "HTTP/1.1"),
new Header("content-type", "text/html; charset=UTF-8")
);
stream.reply(responseHeaders, true);
BufferedSink out = Okio.buffer(stream.getSink());
for (File file : files) {
String target = file.isDirectory() ? (file.getName() + "/") : file.getName();
out.writeUtf8("<a href='" + target + "'>" + target + "</a><br>");
}
out.close();
}

private void serveFile(Http2Stream stream, File file) throws IOException {
List<Header> responseHeaders = Arrays.asList(
new Header(":status", "200"),
new Header(":version", "HTTP/1.1"),
new Header("content-type", contentType(file))
);
stream.reply(responseHeaders, true);
Source source = Okio.source(file);
try {
BufferedSink out = Okio.buffer(stream.getSink());
out.writeAll(source);
out.close();
} finally {
Util.closeQuietly(source);
}
}

private String contentType(File file) {
if (file.getName().endsWith(".css")) return "text/css";
if (file.getName().endsWith(".gif")) return "image/gif";
if (file.getName().endsWith(".html")) return "text/html";
if (file.getName().endsWith(".jpeg")) return "image/jpeg";
if (file.getName().endsWith(".jpg")) return "image/jpeg";
if (file.getName().endsWith(".js")) return "application/javascript";
if (file.getName().endsWith(".png")) return "image/png";
return "text/plain";
}

public static void main(String... args) throws Exception {
if (args.length != 1 || args[0].startsWith("-")) {
System.out.println("Usage: FramedServer <base directory>");
return;
}

Http2Server server = new Http2Server(new File(args[0]),
SslClient.localhost().sslContext.getSocketFactory());
server.run();
}
}
Loading