Skip to content
Merged
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
43 changes: 17 additions & 26 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -92,22 +92,15 @@ sourceSets {
}
}

def getGitVersion () {
def output = new ByteArrayOutputStream()
exec {
commandLine 'git', 'rev-list', '--tags', '--max-count=1'
standardOutput = output
}
def revision = output.toString().trim()
output.reset()
exec {
commandLine 'git', 'describe', '--tags', revision
standardOutput = output
}
return output.toString().trim()
}
// Use a lazy Provider to get the git version. This is the modern, configuration-cache-friendly approach.
def gitVersionProvider = project.providers.exec {
// 1. Describe the latest revision with a tag
commandLine = ['git', 'describe', '--tags', '--always']
ignoreExitValue = true // Don't fail the build if git fails (e.g., no tags exist)
}.standardOutput.asText.map { it.trim() }

version = getGitVersion()
// Apply the git version to your project
version = gitVersionProvider.get()

task showGitVersion {
doLast {
Expand All @@ -116,9 +109,6 @@ task showGitVersion {
}

build {
doFirst {
getGitVersion
}
}

jar {
Expand Down Expand Up @@ -181,16 +171,17 @@ task runSimpleFileServer(type: JavaExec) {
}
dependsOn testClasses
classpath sourceSets.test.runtimeClasspath
main "SimpleFileServer"

// FIX 1: Use 'mainClass' instead of 'main'
// FIX 2: Replace "SimpleFileServer" with the FULLY QUALIFIED class name
// (e.g., if it's in a package named com.example)
mainClass = "com.example.SimpleFileServer"

args = ['fileserver','443','fileserver/logfile.txt']
// args = ['fileserver','8080','fileserver/logfile.txt']
javaLauncher = javaToolchains.launcherFor {

javaLauncher = javaToolchains.launcherFor {
languageVersion = JavaLanguageVersion.of(23)
}
// debugOptions {
// enabled = true
// suspend = true
// }
}

task testJar(type: Jar) {
Expand All @@ -205,7 +196,7 @@ task runAllTests(type: Test) {
}

publish {
// dependsOn runAllTests
dependsOn runAllTests
}

publishing {
Expand Down
3 changes: 3 additions & 0 deletions src/main/java/robaho/net/httpserver/Code.java
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
public class Code {

public static final int HTTP_CONTINUE = 100;
public static final int HTTP_SWITCHING_PROTOCOLS = 101;
public static final int HTTP_OK = 200;
public static final int HTTP_CREATED = 201;
public static final int HTTP_ACCEPTED = 202;
Expand Down Expand Up @@ -71,6 +72,8 @@ static String msg(int code) {
return " OK";
case HTTP_CONTINUE:
return " Continue";
case HTTP_SWITCHING_PROTOCOLS:
return " Switching Protocols";
case HTTP_CREATED:
return " Created";
case HTTP_ACCEPTED:
Expand Down
70 changes: 37 additions & 33 deletions src/main/java/robaho/net/httpserver/ExchangeImpl.java
Original file line number Diff line number Diff line change
Expand Up @@ -40,8 +40,6 @@

import com.sun.net.httpserver.*;

import robaho.net.httpserver.websockets.WebSocketHandler;

class ExchangeImpl {

Headers reqHdrs, rspHdrs;
Expand Down Expand Up @@ -69,7 +67,8 @@ class ExchangeImpl {

private static final String HEAD = "HEAD";
private static final String CONNECT = "CONNECT";

private static final String HEADER_CONNECTION = "Connection";
private static final String HEADER_CONNECTION_UPGRADE = "Upgrade";
/*
* streams which take care of the HTTP protocol framing
* and are passed up to higher layers
Expand All @@ -85,7 +84,7 @@ class ExchangeImpl {
Map<String, Object> attributes;
int rcode = -1;
HttpPrincipal principal;
final boolean websocket;
boolean connectionUpgraded = false;

ExchangeImpl(
String m, URI u, Request req, long len, HttpConnection connection) throws IOException {
Expand All @@ -97,11 +96,6 @@ class ExchangeImpl {
this.method = m;
this.uri = u;
this.connection = connection;
this.websocket = WebSocketHandler.isWebsocketRequested(this.reqHdrs);
if (this.websocket) {
// length is indeterminate
len = -1;
}
this.reqContentLen = len;
/* ros only used for headers, body written directly to stream */
this.ros = req.outputStream();
Expand Down Expand Up @@ -135,6 +129,9 @@ private boolean isHeadRequest() {
private boolean isConnectRequest() {
return CONNECT.equals(getRequestMethod());
}
private boolean isUpgradeRequest() {
return HEADER_CONNECTION_UPGRADE.equalsIgnoreCase(reqHdrs.getFirst(HEADER_CONNECTION));
}

public void close() {
if (closed) {
Expand Down Expand Up @@ -170,7 +167,7 @@ public InputStream getRequestBody() {
if (uis != null) {
return uis;
}
if (websocket || isConnectRequest()) {
if (connectionUpgraded || isConnectRequest() || isUpgradeRequest()) {
// connection cannot be re-used
uis = ris;
} else if (reqContentLen == -1L) {
Expand Down Expand Up @@ -232,7 +229,6 @@ public void sendResponseHeaders(int rCode, long contentLen)
ros.write(statusLine.getBytes(ISO_CHARSET));
boolean noContentToSend = false; // assume there is content
boolean noContentLengthHeader = false; // must not send Content-length is set
rspHdrs.set("Date", ActivityTimer.dateAndTime());

Integer bufferSize = (Integer)this.getAttribute(Attributes.SOCKET_WRITE_BUFFER);
if(bufferSize!=null) {
Expand All @@ -242,19 +238,21 @@ public void sendResponseHeaders(int rCode, long contentLen)
boolean flush = false;

/* check for response type that is not allowed to send a body */
if (rCode == 101) {
logger.log(Level.DEBUG, () -> "switching protocols");

if (contentLen != 0) {
String msg = "sendResponseHeaders: rCode = " + rCode
+ ": forcing contentLen = 0";
logger.log(Level.WARNING, msg);
}
contentLen = 0;
flush = true;

} else if ((rCode >= 100 && rCode < 200) /* informational */
|| (rCode == 204) /* no content */
var informational = rCode >= 100 && rCode < 200;

if (informational) {
if (rCode == 101) {
logger.log(Level.DEBUG, () -> "switching protocols");
if (contentLen != 0) {
String msg = "sendResponseHeaders: rCode = " + rCode
+ ": forcing contentLen = 0";
logger.log(Level.WARNING, msg);
contentLen = 0;
}
connectionUpgraded = true;
}
noContentLengthHeader = true; // the Content-length header must not be set for interim responses as they cannot have a body
} else if ((rCode == 204) /* no content */
|| (rCode == 304)) /* not modified */
{
if (contentLen != -1) {
Expand All @@ -266,6 +264,10 @@ public void sendResponseHeaders(int rCode, long contentLen)
noContentLengthHeader = (rCode != 304);
}

if(!informational) {
rspHdrs.set("Date", ActivityTimer.dateAndTime());
}

if (isHeadRequest() || rCode == 304) {
/*
* HEAD requests or 304 responses should not set a content length by passing it
Expand All @@ -278,14 +280,16 @@ public void sendResponseHeaders(int rCode, long contentLen)
noContentToSend = true;
contentLen = 0;
o.setWrappedStream(new FixedLengthOutputStream(this, ros, contentLen));
} else { /* not a HEAD request or 304 response */
} else if(informational && !connectionUpgraded) {
// don't want to set the stream for 1xx responses, except 101, the handler must call sendResponseHeaders again with the final code
flush = true;
} else if(connectionUpgraded || isConnectRequest()) {
o.setWrappedStream(ros);
close = true;
flush = true;
} else { /* standard response with possible response data */
if (contentLen == 0) {
if (websocket || isConnectRequest()) {
o.setWrappedStream(ros);
close = true;
flush = true;
}
else if (http10) {
if (http10) {
o.setWrappedStream(new UndefLengthOutputStream(this, ros));
close = true;
} else {
Expand Down Expand Up @@ -323,9 +327,9 @@ else if (http10) {

writeHeaders(rspHdrs, ros);
this.rspContentLen = contentLen;
sentHeaders = true;
sentHeaders = !informational;
if(logger.isLoggable(Level.TRACE)) {
logger.log(Level.TRACE, "Sent headers: noContentToSend=" + noContentToSend);
logger.log(Level.TRACE, "sendResponseHeaders(), code="+rCode+", noContentToSend=" + noContentToSend + ", contentLen=" + contentLen);
}
if(flush) {
ros.flush();
Expand Down
9 changes: 7 additions & 2 deletions src/main/java/robaho/net/httpserver/ServerImpl.java
Original file line number Diff line number Diff line change
Expand Up @@ -862,12 +862,17 @@ void sendReply(
builder.append("HTTP/1.1 ")
.append(code).append(Code.msg(code)).append("\r\n");

var informational = (code >= 100 && code < 200);

if (text != null && text.length() != 0) {
builder.append("Content-length: ")
.append(text.length()).append("\r\n")
.append("Content-type: text/html\r\n");
} else {
builder.append("Content-length: 0\r\n");
if (!informational) {
// no body for 1xx responses
builder.append("Content-length: 0\r\n");
}
text = "";
}
if (closeNow) {
Expand Down Expand Up @@ -898,7 +903,7 @@ void logReply(int code, String requestStr, String text) {
} else {
r = requestStr;
}
logger.log(Level.DEBUG, () -> "reply "+ r + " [" + code + " " + Code.msg(code) + "] (" + (text!=null ? text : "") + ")");
logger.log(Level.DEBUG, () -> "reply "+ r + " [" + code + Code.msg(code) + "] (" + (text!=null ? text : "") + ")");
}

void delay() {
Expand Down
Loading