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);