Skip to content

Commit

Permalink
Add parse-x-www-form-urlencoded.
Browse files Browse the repository at this point in the history
  • Loading branch information
andrewchambers committed Oct 24, 2020
1 parent ba672e7 commit 513c003
Show file tree
Hide file tree
Showing 3 changed files with 103 additions and 5 deletions.
71 changes: 71 additions & 0 deletions circlet.c
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
#include <janet.h>
#include "mongoose.h"
#include <stdio.h>
#if !defined(__FreeBSD__)
#include <alloca.h>
#endif

typedef struct {
struct mg_connection *conn;
Expand Down Expand Up @@ -295,10 +298,78 @@ static Janet cfun_bind_http(int32_t argc, Janet *argv) {
return argv[0];
}

static int decode_nibble(uint8_t b) {
if (b >= '0' && b <= '9')
return b - '0';
if (b >= 'a' && b <= 'f')
return 10 + b - 'a';
if (b >= 'A' && b <= 'F')
return 10 + b - 'A';
return 0;
}

static Janet unescape_x_www_form_urlencoded(const uint8_t *str, size_t len) {
size_t nwritten = 0;
uint8_t *tmp = NULL;
#define NALLOCA 128
if (len >= NALLOCA)
tmp = janet_smalloc(len);
else
tmp = alloca(len);

int st = 0;
uint8_t nb1, nb2;
for (size_t i = 0; i < len; i++) {
uint8_t c = str[i];
switch (st) {
case 0:
switch (c) {
case '+':
tmp[nwritten++] = ' ';
break;
case '%':
st = 1;
break;
default:
tmp[nwritten++] = c;
break;
}
break;
case 1:
st = 2;
nb1 = decode_nibble(c);
break;
case 2:
st = 0;
nb2 = decode_nibble(c);
tmp[nwritten++] = (nb1 << 4) | nb2;
break;
default:
abort();
}
}

Janet unescaped = janet_stringv(tmp, nwritten);

if (len >= NALLOCA)
janet_sfree(tmp);

return unescaped;
#undef NALLOCA
}

static Janet cfun_escape_x_www_form_urlencoded(int argc, Janet *argv) {
janet_fixarity(argc, 1);
JanetByteView bv = janet_getbytes(argv, 0);
return unescape_x_www_form_urlencoded(bv.bytes, bv.len);
}


static const JanetReg cfuns[] = {
{"manager", cfun_manager, NULL},
{"poll", cfun_poll, NULL},
{"bind-http", cfun_bind_http, NULL},
{"escape-x-www-form-urlencoded", cfun_escape_x_www_form_urlencoded, NULL},
{NULL, NULL, NULL}
};

Expand Down
25 changes: 20 additions & 5 deletions circlet_lib.janet
Original file line number Diff line number Diff line change
Expand Up @@ -40,11 +40,12 @@
the handler function of the next middleware"
[nextmw]
(def grammar
(peg/compile
{:content '(some (if-not (set "=;") 1))
:eql "="
:sep '(between 1 2 (set "; "))
:main '(some (* (<- :content) :eql (<- :content) (? :sep)))}))
(comptime
(peg/compile
{:content '(some (if-not (set "=;") 1))
:eql "="
:sep '(between 1 2 (set "; "))
:main '(some (* (<- :content) :eql (<- :content) (? :sep)))})))
(fn [req]
(-> req
(put :cookies
Expand All @@ -55,6 +56,20 @@
{}))
nextmw)))

(defn parse-x-www-form-urlencoded
[q]
"Parse x-www-form-urlencoded bytes returning a table or nil."
(def grammar
(comptime
(peg/compile ~{
:main (sequence (opt :query) (not 1))
:query (sequence :pair (any (sequence "&" :pair)))
:pair (sequence (cmt (capture :key) ,escape-x-www-form-urlencoded) "=" (cmt (capture :value) ,escape-x-www-form-urlencoded))
:key (any (sequence (not "=") 1))
:value (any (sequence (not "&") 1))})))
(when-let [matches (peg/match grammar q)]
(table ;matches)))

(defn server
"Creates a simple http server. handler parameter is the function handling the
requests. It could be middleware. port is the number of the port the server
Expand Down
12 changes: 12 additions & 0 deletions test/parse-x-www-form-urlencoded.janet
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
(import build/circlet :as circlet)

(def tests [
["" @{}]
["abc=5&%20+=" @{"abc" "5" " " ""}]
["a=b" @{"a" "b"}]
])

(each tc tests
(def r (circlet/parse-x-www-form-urlencoded (tc 0)))
(unless (deep= r (tc 1))
(errorf "fail: %j != %j" r (tc 1))))

0 comments on commit 513c003

Please sign in to comment.