Skip to content
Open
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
85 changes: 76 additions & 9 deletions src/main/java/org/example/ConnectionHandler.java
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,21 @@
import org.example.filter.IpFilter;
import org.example.httpparser.HttpParser;
import org.example.httpparser.HttpRequest;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.example.filter.Filter;
import org.example.filter.FilterChainImpl;
import org.example.http.HttpResponseBuilder;
import org.example.config.ConfigLoader;

import java.io.IOException;
import java.net.Socket;
import java.net.URLDecoder;
import java.nio.charset.StandardCharsets;

public class ConnectionHandler implements AutoCloseable {

Expand Down Expand Up @@ -40,7 +46,6 @@ private List<Filter> buildFilters() {
if (Boolean.TRUE.equals(ipFilterConfig.enabled())) {
list.add(createIpFilterFromConfig(ipFilterConfig));
}
// Add more filters here...
return list;
}

Expand All @@ -58,12 +63,18 @@ public void runConnectionHandler() throws IOException {
parser.parseRequest();
parser.parseHttp();

// --- ISSUE FIX ---
String rawUri = parser.getUri();
String pathOnly = extractPath(rawUri);
Map<String, List<String>> queryParams = parseQueryParams(rawUri);

HttpRequest request = new HttpRequest(
parser.getMethod(),
parser.getUri(),
pathOnly,
parser.getVersion(),
parser.getHeadersMap(),
""
"",
queryParams
);

String clientIp = client.getInetAddress().getHostAddress();
Expand All @@ -80,16 +91,14 @@ public void runConnectionHandler() throws IOException {
return;
}

resolveTargetFile(parser.getUri());
resolveTargetFile(request.getPath());
sfh.sendGetRequest(client.getOutputStream(), uri);
}

private HttpResponseBuilder applyFilters(HttpRequest request) {
HttpResponseBuilder response = new HttpResponseBuilder();

FilterChainImpl chain = new FilterChainImpl(filters);
chain.doFilter(request, response);

return response;
}

Expand All @@ -101,6 +110,67 @@ private void resolveTargetFile(String uri) {
}
}

// -----------------------------
// Query parsing without split()
// -----------------------------

private static String extractPath(String uri) {
if (uri == null || uri.isEmpty()) return "/";
int q = uri.indexOf('?');
String path = (q >= 0) ? uri.substring(0, q) : uri;
return path.isEmpty() ? "/" : path;
}
Comment thread
Ericthilen marked this conversation as resolved.

private static Map<String, List<String>> parseQueryParams(String uri) {
Map<String, List<String>> params = new HashMap<>();
if (uri == null) return params;

int questionMarkIndex = uri.indexOf('?');
if (questionMarkIndex < 0 || questionMarkIndex == uri.length() - 1) {
return params;
}

String query = uri.substring(questionMarkIndex + 1);

int start = 0;
while (start < query.length()) {

int ampIndex = query.indexOf('&', start);
if (ampIndex == -1) {
ampIndex = query.length();
}

String pair = query.substring(start, ampIndex);

int equalsIndex = pair.indexOf('=');

if (pair.isEmpty()) {
start = ampIndex + 1;
continue;
}

String key;
String value;

if (equalsIndex >= 0) {
key = pair.substring(0, equalsIndex);
value = pair.substring(equalsIndex + 1);
} else {
key = pair;
value = "";
}

key = URLDecoder.decode(key, StandardCharsets.UTF_8);
value = URLDecoder.decode(value, StandardCharsets.UTF_8);

params.computeIfAbsent(key, k -> new ArrayList<>()).add(value);
Comment thread
Ericthilen marked this conversation as resolved.

start = ampIndex + 1;
}

return params;
}

@Override
public void close() throws Exception {
client.close();
Expand All @@ -109,19 +179,16 @@ public void close() throws Exception {
private IpFilter createIpFilterFromConfig(AppConfig.IpFilterConfig config) {
IpFilter filter = new IpFilter();

// Set mode
if ("ALLOWLIST".equalsIgnoreCase(config.mode())) {
filter.setMode(IpFilter.FilterMode.ALLOWLIST);
} else {
filter.setMode(IpFilter.FilterMode.BLOCKLIST);
}

// Add blocked IPs
for (String ip : config.blockedIps()) {
filter.addBlockedIp(ip);
}

// Add allowed IPs
for (String ip : config.allowedIps()) {
filter.addAllowedIp(ip);
}
Expand Down
108 changes: 71 additions & 37 deletions src/main/java/org/example/httpparser/HttpRequest.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,48 +2,82 @@

import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/*
*
*This class groups together all information about a request that the server needs
*
* This class groups together all information about a request that the server needs
*/

public class HttpRequest {

private final String method;
private final String path;
private final String version;
private final Map<String, String> headers;
private final String body;
private final Map<String, Object> attributes = new HashMap<>();

public HttpRequest(String method,
String path,
String version,
Map<String, String> headers,
String body) {
this.method = method;
this.path = path;
this.version = version;
this.headers = headers != null ? Map.copyOf(headers) : Collections.emptyMap();
this.body = body;
}

public String getMethod() {
return method; }
public String getPath() {
return path; }
public String getVersion() {
return version; }
public Map<String, String> getHeaders() {
return headers; }
public String getBody() {
return body; }
public void setAttribute(String key, Object value) {
attributes.put(key, value);
}
public Object getAttribute(String key) {
return attributes.get(key);
}
private final String method;
private final String path;
private final String version;
private final Map<String, String> headers;
private final String body;

private final Map<String, List<String>> queryParams;

private final Map<String, Object> attributes = new HashMap<>();

public HttpRequest(String method,
String path,
String version,
Map<String, String> headers,
String body) {
this(method, path, version, headers, body, Collections.emptyMap());
}

public HttpRequest(String method,
String path,
String version,
Map<String, String> headers,
String body,
Map<String, List<String>> queryParams) {

this.method = method;
this.path = path;
this.version = version;
this.headers = headers != null ? Map.copyOf(headers) : Collections.emptyMap();
this.body = body;
this.queryParams = queryParams != null ? Map.copyOf(queryParams) : Collections.emptyMap();
}

public String getMethod() {
return method;
}

public String getPath() {
return path;
}

public String getVersion() {
return version;
}

public Map<String, String> getHeaders() {
return headers;
}

public String getBody() {
return body;
}

public Map<String, List<String>> getQueryParams() {
return queryParams;
}

public List<String> getQueryParam(String key) {
return queryParams.getOrDefault(key, List.of());
}

public void setAttribute(String key, Object value) {
attributes.put(key, value);
}

public Object getAttribute(String key) {
return attributes.get(key);
}
}