Commit ce5bb8abe31e89b7c63ab33628c842184d0fde5b

Thomas de Grivel 2024-09-14T17:58:32

http_response_set_header

diff --git a/http/http_response.c b/http/http_response.c
index 6547a69..336a30f 100644
--- a/http/http_response.c
+++ b/http/http_response.c
@@ -277,3 +277,78 @@ sw http_response_buf_write (const s_http_response *response,
   }
   return result;
 }
+
+void http_response_clean (s_http_response *res)
+{
+  str_clean(&res->protocol);
+  str_clean(&res->message);
+  list_delete_all(res->headers);
+  tag_clean(&res->body);
+}
+
+s_tag * http_response_find_header (const s_http_response *res,
+                                   const s_str *key)
+{
+  s_list *h;
+  assert(res);
+  assert(key);
+  h = res->headers;
+  while (h) {
+    if (h->tag.type != TAG_TUPLE ||
+        h->tag.data.tuple.count != 2 ||
+        h->tag.data.tuple.tag->type != TAG_STR) {
+      err_write_1("http_response_find_header: invalid header: ");
+      err_inspect_tag(&h->tag);
+      err_write_1("\n");
+      return NULL;
+    }
+    if (! compare_str_case_insensitive(h->tag.data.tuple.tag->data.str,
+                                       key))
+      return h->tag.data.tuple.tag + 1;
+    h = list_next(h);
+  }
+  return NULL;
+}
+
+s_http_response * http_response_init_copy (s_http_response *res,
+                                           const s_http_response *src)
+{
+  s_http_response tmp = {0};
+  if (! str_init_copy(&tmp.protocol, &src->protocol))
+    return NULL;
+  tmp.code = src->code;
+  if (! str_init_copy(&tmp.message, &src->message))
+    goto clean;
+  if (! list_init_copy(&tmp.headers, &src->headers))
+    goto clean;
+  if (! tag_init_copy(&tmp.body, &src->body))
+    goto clean;
+  *res = tmp;
+  return res;
+ clean:
+  http_response_clean(&tmp);
+  return NULL;
+}
+
+s_http_response * http_response_set_header (const s_http_response *res,
+                                            const s_str *key,
+                                            const s_str *value,
+                                            s_http_response *dest)
+{
+  s_tag *header;
+  s_http_response tmp = {0};
+  if (! http_response_init_copy(&tmp, res))
+    return NULL;
+  if ((header = http_response_find_header(&tmp, key))) {
+    tag_clean(header);
+    tag_init_str_copy(header, value);
+  }
+  else {
+    if (! (tmp.headers = list_new_tuple(2, tmp.headers)))
+      goto clean;
+    tag_init_str_copy(tmp.headers->tag.data.tuple.tag, key);
+    tag_init_str_copy(tmp.headers->tag.data.tuple.tag + 1, value);
+  }
+  *dest = tmp;
+  return dest;
+}
diff --git a/http/http_response.h b/http/http_response.h
index 4fef1f1..b28aff9 100644
--- a/http/http_response.h
+++ b/http/http_response.h
@@ -15,7 +15,20 @@
 
 #include "types.h"
 
-sw http_response_buf_write (const s_http_response *response,
-                            s_buf *buf, bool send_body);
+/* Stack-allocation compatible functions, call http_response_clean
+   after use. */
+void              http_response_clean (s_http_response *res);
+s_http_response * http_response_init_copy (s_http_response *res,
+                                           const s_http_response *src);
+
+/* Observers. */
+sw                http_response_buf_write (const s_http_response *res,
+                                           s_buf *buf, bool send_body);
+s_tag *           http_response_find_header (const s_http_response *res,
+                                             const s_str *key);
+s_http_response * http_response_set_header (const s_http_response *res,
+                                            const s_str *key,
+                                            const s_str *value,
+                                            s_http_response *dest);
 
 #endif /* HTTP_RESPONSE_H */
diff --git a/lib/kc3/0.1/http/response.kc3 b/lib/kc3/0.1/http/response.kc3
index 5f053df..a46a557 100644
--- a/lib/kc3/0.1/http/response.kc3
+++ b/lib/kc3/0.1/http/response.kc3
@@ -20,4 +20,7 @@ defmodule HTTP.Response do
   def buf_write = cfn Sw "http_response_buf_write" (HTTP.Response, Buf,
     Bool)
 
+  def set_header = cfn HTTP.Response "http_response_set_header"
+    (HTTP.Response, Str, Str, Result)
+
 end
diff --git a/lib/kc3/0.1/httpd.kc3 b/lib/kc3/0.1/httpd.kc3
index ad68f08..9014a2f 100644
--- a/lib/kc3/0.1/httpd.kc3
+++ b/lib/kc3/0.1/httpd.kc3
@@ -43,6 +43,10 @@ defmodule HTTPd do
       if req do
         router = route_request(req)
         response = router(req)
+        response = HTTP.Response.set_header(response,
+          "Connection", "Keep-Alive")
+        response = HTTP.Response.set_header(response,
+          "Keep-Alive", "timeout=5, max=1000")
         r = HTTP.Response.buf_write(response, client.buf_rw.w,
           req.method != HEAD)
         client_addr = if client.addr_str != "127.0.0.1" do
@@ -60,6 +64,8 @@ defmodule HTTPd do
     end
   end
 
+  def timeout = %Time{tv_sec: 5}
+
   def acceptor = fn (server_socket, events, acceptor_ev, void) do
     if List.has?(events, :read) do
       client = Socket.Buf.accept(%Socket{fd: server_socket})
@@ -78,7 +84,7 @@ defmodule HTTPd do
     end
   }
 
-  def timeout = %Time{}
+  def time_zero = %Time{}
 
   def server = fn (host, port) {
     daemonize()
@@ -87,7 +93,7 @@ defmodule HTTPd do
     puts("KC3 HTTPd: listening on #{host}:#{port}")
     acceptor_ev = Event.new(event_base, socket.fd, [:read, :persist],
                             acceptor, void)
-    r = Event.add(acceptor_ev, timeout)
+    r = Event.add(acceptor_ev, time_zero)
     r = Event.dispatch(event_base)
     if r do
       e = errno()
diff --git a/libkc3/compare.c b/libkc3/compare.c
index 72951e6..a3a7d68 100644
--- a/libkc3/compare.c
+++ b/libkc3/compare.c
@@ -10,14 +10,16 @@
  * AUTHOR BE CONSIDERED LIABLE FOR THE USE AND PERFORMANCE OF
  * THIS SOFTWARE.
  */
-#include "assert.h"
 #include <string.h>
+#include "assert.h"
+#include "character.h"
 #include "compare.h"
 #include "complex.h"
 #include "data.h"
 #include "integer.h"
 #include "list.h"
 #include "ratio.h"
+#include "str.h"
 #include "tag.h"
 
 #define COMPARE_DEF(type)                       \
@@ -490,6 +492,37 @@ s8 compare_str (const s_str *a, const s_str *b)
   return 0;
 }
 
+s8 compare_str_case_insensitive (const s_str *a, const s_str *b)
+{
+  character ac;
+  s_str     as;
+  character bc;
+  s_str     bs;
+  sw r;
+  sw r2;
+  assert(a);
+  assert(b);
+  if (a == b)
+    return 0;
+  as = *a;
+  bs = *b;
+  while (1) {
+    r = str_read_character_utf8(&as, &ac);
+    r2 = str_read_character_utf8(&bs, &bc);
+    if (r <= 0 && r2 <= 0)
+      return 0;
+    if (r <= 0)
+      return -1;
+    if (r2 <= 0)
+      return 1;
+    ac = character_to_lower(ac);
+    bc = character_to_lower(bc);
+    if ((r = compare_character(ac, bc)))
+      return r;
+  }
+  return COMPARE_ERROR;
+}
+
 s8 compare_struct (const s_struct *a, const s_struct *b)
 {
   uw i;
diff --git a/libkc3/compare.h b/libkc3/compare.h
index da5b172..12b8fc5 100644
--- a/libkc3/compare.h
+++ b/libkc3/compare.h
@@ -55,6 +55,7 @@ COMPARE_PROTOTYPE(s32);
 COMPARE_PROTOTYPE(s64);
 COMPARE_PROTOTYPE(sw);
 s8 compare_str (const s_str *a, const s_str *b);
+s8 compare_str_case_insensitive (const s_str *a, const s_str *b);
 s8 compare_struct (const s_struct *a, const s_struct *b);
 s8 compare_struct_type (const s_struct_type *a, const s_struct_type *b);
 s8 compare_sym (const s_sym *a, const s_sym *b);