From 83281bf2de4adcea16b8281857fbfaf02dbab2bb Mon Sep 17 00:00:00 2001 From: hanez Date: Mon, 29 Dec 2025 17:24:08 +0100 Subject: [PATCH] Added GET and POST support to HTTPServer class. (0.37.32) --- CMakeLists.txt | 2 +- examples/data/htdocs/info.fun | 30 +++++++++++++++++++++++++ examples/extra/http_server_test.fun | 32 +++++++++++++++++++++++++++ lib/net/http_server.fun | 34 ++++++++++++++++++++++++----- 4 files changed, 92 insertions(+), 6 deletions(-) create mode 100755 examples/extra/http_server_test.fun diff --git a/CMakeLists.txt b/CMakeLists.txt index 473dd62..dd7dbf9 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,5 +1,5 @@ cmake_minimum_required(VERSION 3.10) -project(fun VERSION 0.37.31 LANGUAGES C) +project(fun VERSION 0.37.32 LANGUAGES C) set(CMAKE_C_STANDARD 99) set(CMAKE_C_STANDARD_REQUIRED ON) diff --git a/examples/data/htdocs/info.fun b/examples/data/htdocs/info.fun index 4473ec0..65e64cb 100644 --- a/examples/data/htdocs/info.fun +++ b/examples/data/htdocs/info.fun @@ -9,6 +9,8 @@ * Added: 2025-12-28 */ +#include + print("") print("

Fun Environment Information

") print("

Current Path: " + env("PATH") + "

") @@ -25,4 +27,32 @@ while i < len(all_keys) print("
  • " + key + "=" + all_env[key] + "
  • ") i = i + 1 print("") +print("

    GET Variables:

    ") +print("") +print("

    POST Variables:

    ") +print("") print("") diff --git a/examples/extra/http_server_test.fun b/examples/extra/http_server_test.fun new file mode 100755 index 0000000..ad3ab64 --- /dev/null +++ b/examples/extra/http_server_test.fun @@ -0,0 +1,32 @@ +#include + +c = TcpClient() +if (c.connect("127.0.0.1", 8080)) + print("Connecting to server...") + // Test GET + print("Testing GET...") + c.send("GET /info.fun?foo=bar&baz=qux HTTP/1.1\r\nHost: localhost\r\n\r\n") + resp = c.recv_all(4096) + print("GET Response contains foo=bar: " + to_string(find(resp, "foo = bar") >= 0)) + print("GET Response contains baz=qux: " + to_string(find(resp, "baz = qux") >= 0)) + + c.close() +else + print("Failed to connect to server") + +if (c.connect("127.0.0.1", 8080)) + // Test POST + print("Testing POST...") + body = "postfoo=postbar&postbaz=postqux" + req = "POST /info.fun HTTP/1.1\r\n" + req = req + "Host: localhost\r\n" + req = req + "Content-Length: " + to_string(len(body)) + "\r\n" + req = req + "\r\n" + req = req + body + c.send(req) + resp = c.recv_all(4096) + print("POST Response contains postfoo=postbar: " + to_string(find(resp, "postfoo = postbar") >= 0)) + print("POST Response contains postbaz=postqux: " + to_string(find(resp, "postbaz = postqux") >= 0)) + c.close() +else + print("Failed to connect to server for POST") diff --git a/lib/net/http_server.fun b/lib/net/http_server.fun index 3d36b03..dc78dac 100644 --- a/lib/net/http_server.fun +++ b/lib/net/http_server.fun @@ -51,20 +51,44 @@ class HTTPServer(number port) sock_close(fd) return 0 - method = parts[0] - path = parts[1] + method = str_trim(parts[0]) + full_path = str_trim(parts[1]) + + path = full_path + query_string = "" + q_pos = find(full_path, "?") + if (q_pos >= 0) + path = substr(full_path, 0, q_pos) + query_string = substr(full_path, q_pos + 1, len(full_path) - q_pos - 1) if (path == "/") path = "/index.html" - full_path = this.htdocs + path + file_path = this.htdocs + path + + post_data = "" + if (method == "POST") + // Find the end of headers (marked by \r\n\r\n or \n\n) + header_end = find(request, "\r\n\r\n") + if (header_end >= 0) + post_data = substr(request, header_end + 4, len(request) - header_end - 4) + else + header_end = find(request, "\n\n") + if (header_end >= 0) + post_data = substr(request, header_end + 2, len(request) - header_end - 2) content = "" if (str_ends_with(path, ".fun")) - res = proc_run("fun" + " " + full_path) + env_vars = "" + if (len(query_string) > 0) + env_vars = "QUERY_STRING='" + query_string + "' " + if (len(post_data) > 0) + env_vars = env_vars + "POST_DATA='" + post_data + "' " + + res = proc_run(env_vars + " " + "fun" + " " + file_path) content = res["out"] else - content = read_file(full_path) + content = read_file(file_path) if (len(content) > 0) this.send_response(fd, 200, "OK", content)